├── .dockerignore
├── .gitattributes
├── .gitignore
├── .ruby-version
├── Dockerfile
├── Gemfile
├── Gemfile.lock
├── Procfile.dev
├── README.md
├── Rakefile
├── app
├── assets
│ ├── builds
│ │ └── .keep
│ ├── config
│ │ └── manifest.js
│ ├── images
│ │ ├── .keep
│ │ ├── dotsIcon.svg
│ │ ├── eye-off.svg
│ │ └── eye.svg
│ └── stylesheets
│ │ ├── application.css
│ │ └── application.tailwind.css
├── controllers
│ ├── application_controller.rb
│ ├── concerns
│ │ └── .keep
│ ├── reasons_controller.rb
│ └── storefronts_controller.rb
├── helpers
│ ├── application_helper.rb
│ └── storefronts_helper.rb
├── javascript
│ ├── application.js
│ └── controllers
│ │ ├── application.js
│ │ ├── drag_controller.js
│ │ ├── index.js
│ │ ├── modal_controller.js
│ │ └── nested_form_controller.js
├── models
│ ├── application_record.rb
│ ├── concerns
│ │ └── .keep
│ ├── reason.rb
│ └── storefront.rb
└── views
│ ├── layouts
│ └── application.html.erb
│ └── storefronts
│ ├── _form.html.erb
│ ├── _reason.html.erb
│ ├── _storefront.html.erb
│ ├── _storefront.json.jbuilder
│ ├── edit.html.erb
│ ├── index.html.erb
│ ├── index.json.jbuilder
│ ├── new.html.erb
│ ├── show.html.erb
│ └── show.json.jbuilder
├── bin
├── bundle
├── dev
├── docker-entrypoint
├── importmap
├── rails
├── rake
└── setup
├── config.ru
├── config
├── application.rb
├── boot.rb
├── credentials.yml.enc
├── database.yml
├── environment.rb
├── environments
│ ├── development.rb
│ ├── production.rb
│ └── test.rb
├── importmap.rb
├── initializers
│ ├── assets.rb
│ ├── content_security_policy.rb
│ ├── filter_parameter_logging.rb
│ ├── inflections.rb
│ ├── permissions_policy.rb
│ ├── simple_form.rb
│ └── simple_form_tailwind.rb
├── locales
│ ├── en.yml
│ └── simple_form.en.yml
├── puma.rb
├── routes.rb
└── tailwind.config.js
├── db
├── migrate
│ ├── 20231221221744_create_storefronts.rb
│ └── 20231221221802_create_reasons.rb
├── schema.rb
└── seeds.rb
├── lib
├── assets
│ └── .keep
└── tasks
│ └── .keep
├── log
└── .keep
├── package.json
├── public
├── 404.html
├── 422.html
├── 500.html
├── apple-touch-icon-precomposed.png
├── apple-touch-icon.png
├── favicon.ico
└── robots.txt
├── storage
├── .keep
├── development.sqlite3
├── development.sqlite3-shm
└── development.sqlite3-wal
├── test
├── application_system_test_case.rb
├── controllers
│ ├── .keep
│ └── storefronts_controller_test.rb
├── fixtures
│ ├── files
│ │ └── .keep
│ ├── reasons.yml
│ └── storefronts.yml
├── helpers
│ └── .keep
├── integration
│ └── .keep
├── models
│ ├── .keep
│ ├── reason_test.rb
│ └── storefront_test.rb
├── system
│ ├── .keep
│ └── storefronts_test.rb
└── test_helper.rb
├── tmp
├── .keep
├── pids
│ └── .keep
└── storage
│ └── .keep
└── vendor
├── .keep
└── javascript
└── .keep
/.dockerignore:
--------------------------------------------------------------------------------
1 | # See https://docs.docker.com/engine/reference/builder/#dockerignore-file for more about ignoring files.
2 |
3 | # Ignore git directory.
4 | /.git/
5 |
6 | # Ignore bundler config.
7 | /.bundle
8 |
9 | # Ignore all environment files (except templates).
10 | /.env*
11 | !/.env*.erb
12 |
13 | # Ignore all default key files.
14 | /config/master.key
15 | /config/credentials/*.key
16 |
17 | # Ignore all logfiles and tempfiles.
18 | /log/*
19 | /tmp/*
20 | !/log/.keep
21 | !/tmp/.keep
22 |
23 | # Ignore pidfiles, but keep the directory.
24 | /tmp/pids/*
25 | !/tmp/pids/.keep
26 |
27 | # Ignore storage (uploaded files in development and any SQLite databases).
28 | /storage/*
29 | !/storage/.keep
30 | /tmp/storage/*
31 | !/tmp/storage/.keep
32 |
33 | # Ignore assets.
34 | /node_modules/
35 | /app/assets/builds/*
36 | !/app/assets/builds/.keep
37 | /public/assets
38 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | # See https://git-scm.com/docs/gitattributes for more about git attribute files.
2 |
3 | # Mark the database schema as having been generated.
4 | db/schema.rb linguist-generated
5 |
6 | # Mark any vendored files as having been vendored.
7 | vendor/* linguist-vendored
8 | config/credentials/*.yml.enc diff=rails_credentials
9 | config/credentials.yml.enc diff=rails_credentials
10 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files for more about ignoring files.
2 | #
3 | # If you find yourself ignoring temporary files generated by your text editor
4 | # or operating system, you probably want to add a global ignore instead:
5 | # git config --global core.excludesfile '~/.gitignore_global'
6 | /.idea/*
7 |
8 | # Ignore bundler config.
9 | /.bundle
10 |
11 | # Ignore all environment files (except templates).
12 | /.env*
13 | !/.env*.erb
14 |
15 | # Ignore all logfiles and tempfiles.
16 | /log/*
17 | /tmp/*
18 | !/log/.keep
19 | !/tmp/.keep
20 |
21 | # Ignore pidfiles, but keep the directory.
22 | /tmp/pids/*
23 | !/tmp/pids/
24 | !/tmp/pids/.keep
25 |
26 | # Ignore storage (uploaded files in development and any SQLite databases).
27 | /storage/test.sqlite3
28 | !/storage/.keep
29 | /tmp/storage/*
30 | !/tmp/storage/
31 | !/tmp/storage/.keep
32 |
33 | /public/assets
34 |
35 | # Ignore master key for decrypting credentials and more.
36 | /config/master.key
37 |
38 | /app/assets/builds/*
39 | !/app/assets/builds/.keep
40 | /node_modules
--------------------------------------------------------------------------------
/.ruby-version:
--------------------------------------------------------------------------------
1 | 3.2.2
2 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | # syntax = docker/dockerfile:1
2 |
3 | # Make sure RUBY_VERSION matches the Ruby version in .ruby-version and Gemfile
4 | ARG RUBY_VERSION=3.0.1
5 | FROM registry.docker.com/library/ruby:$RUBY_VERSION-slim as base
6 |
7 | # Rails app lives here
8 | WORKDIR /rails
9 |
10 | # Set production environment
11 | ENV RAILS_ENV="production" \
12 | BUNDLE_DEPLOYMENT="1" \
13 | BUNDLE_PATH="/usr/local/bundle" \
14 | BUNDLE_WITHOUT="development"
15 |
16 |
17 | # Throw-away build stage to reduce size of final image
18 | FROM base as build
19 |
20 | # Install packages needed to build gems
21 | RUN apt-get update -qq && \
22 | apt-get install --no-install-recommends -y build-essential git pkg-config
23 |
24 | # Install application gems
25 | COPY Gemfile Gemfile.lock ./
26 | RUN bundle install && \
27 | rm -rf ~/.bundle/ "${BUNDLE_PATH}"/ruby/*/cache "${BUNDLE_PATH}"/ruby/*/bundler/gems/*/.git && \
28 | bundle exec bootsnap precompile --gemfile
29 |
30 | # Copy application code
31 | COPY . .
32 |
33 | # Precompile bootsnap code for faster boot times
34 | RUN bundle exec bootsnap precompile app/ lib/
35 |
36 | # Precompiling assets for production without requiring secret RAILS_MASTER_KEY
37 | RUN SECRET_KEY_BASE_DUMMY=1 ./bin/rails assets:precompile
38 |
39 |
40 | # Final stage for app image
41 | FROM base
42 |
43 | # Install packages needed for deployment
44 | RUN apt-get update -qq && \
45 | apt-get install --no-install-recommends -y curl libsqlite3-0 && \
46 | rm -rf /var/lib/apt/lists /var/cache/apt/archives
47 |
48 | # Copy built artifacts: gems, application
49 | COPY --from=build /usr/local/bundle /usr/local/bundle
50 | COPY --from=build /rails /rails
51 |
52 | # Run and own only the runtime files as a non-root user for security
53 | RUN useradd rails --create-home --shell /bin/bash && \
54 | chown -R rails:rails db log storage tmp
55 | USER rails:rails
56 |
57 | # Entrypoint prepares the database.
58 | ENTRYPOINT ["/rails/bin/docker-entrypoint"]
59 |
60 | # Start the server by default, this can be overwritten at runtime
61 | EXPOSE 3000
62 | CMD ["./bin/rails", "server"]
63 |
--------------------------------------------------------------------------------
/Gemfile:
--------------------------------------------------------------------------------
1 | source "https://rubygems.org"
2 |
3 | ruby "3.2.2"
4 |
5 | # Bundle edge Rails instead: gem "rails", github: "rails/rails", branch: "main"
6 | gem "rails", "~> 7.1.2"
7 |
8 | # The original asset pipeline for Rails [https://github.com/rails/sprockets-rails]
9 | gem "sprockets-rails"
10 |
11 | # Use sqlite3 as the database for Active Record
12 | gem "sqlite3", "~> 1.4"
13 |
14 | # Use the Puma web server [https://github.com/puma/puma]
15 | gem "puma", ">= 5.0"
16 |
17 | # Use JavaScript with ESM import maps [https://github.com/rails/importmap-rails]
18 | gem "importmap-rails"
19 |
20 | # Hotwire's SPA-like page accelerator [https://turbo.hotwired.dev]
21 | gem "turbo-rails"
22 |
23 | # Hotwire's modest JavaScript framework [https://stimulus.hotwired.dev]
24 | gem "stimulus-rails"
25 |
26 | # Use Tailwind CSS [https://github.com/rails/tailwindcss-rails]
27 | gem "tailwindcss-rails"
28 |
29 | # Build JSON APIs with ease [https://github.com/rails/jbuilder]
30 | gem "jbuilder"
31 |
32 | gem 'simple_form'
33 | gem 'acts_as_list'
34 |
35 | # Use Kredis to get higher-level data types in Redis [https://github.com/rails/kredis]
36 | # gem "kredis"
37 |
38 | # Use Active Model has_secure_password [https://guides.rubyonrails.org/active_model_basics.html#securepassword]
39 | # gem "bcrypt", "~> 3.1.7"
40 |
41 | # Windows does not include zoneinfo files, so bundle the tzinfo-data gem
42 | gem "tzinfo-data", platforms: %i[ mswin mswin64 mingw x64_mingw jruby ]
43 |
44 | # Reduces boot times through caching; required in config/boot.rb
45 | gem "bootsnap", require: false
46 |
47 | group :development, :test do
48 | # See https://guides.rubyonrails.org/debugging_rails_applications.html#debugging-with-the-debug-gem
49 | gem "debug", platforms: %i[ mri mswin mswin64 mingw x64_mingw ]
50 | end
51 |
52 | group :development do
53 | # Use console on exceptions pages [https://github.com/rails/web-console]
54 | gem "web-console"
55 |
56 | # Add speed badges [https://github.com/MiniProfiler/rack-mini-profiler]
57 | # gem "rack-mini-profiler"
58 |
59 | # Speed up commands on slow machines / big apps [https://github.com/rails/spring]
60 | # gem "spring"
61 | end
62 |
63 | group :test do
64 | # Use system testing [https://guides.rubyonrails.org/testing.html#system-testing]
65 | gem "capybara"
66 | gem "selenium-webdriver"
67 | end
68 |
--------------------------------------------------------------------------------
/Gemfile.lock:
--------------------------------------------------------------------------------
1 | GEM
2 | remote: https://rubygems.org/
3 | specs:
4 | actioncable (7.1.2)
5 | actionpack (= 7.1.2)
6 | activesupport (= 7.1.2)
7 | nio4r (~> 2.0)
8 | websocket-driver (>= 0.6.1)
9 | zeitwerk (~> 2.6)
10 | actionmailbox (7.1.2)
11 | actionpack (= 7.1.2)
12 | activejob (= 7.1.2)
13 | activerecord (= 7.1.2)
14 | activestorage (= 7.1.2)
15 | activesupport (= 7.1.2)
16 | mail (>= 2.7.1)
17 | net-imap
18 | net-pop
19 | net-smtp
20 | actionmailer (7.1.2)
21 | actionpack (= 7.1.2)
22 | actionview (= 7.1.2)
23 | activejob (= 7.1.2)
24 | activesupport (= 7.1.2)
25 | mail (~> 2.5, >= 2.5.4)
26 | net-imap
27 | net-pop
28 | net-smtp
29 | rails-dom-testing (~> 2.2)
30 | actionpack (7.1.2)
31 | actionview (= 7.1.2)
32 | activesupport (= 7.1.2)
33 | nokogiri (>= 1.8.5)
34 | racc
35 | rack (>= 2.2.4)
36 | rack-session (>= 1.0.1)
37 | rack-test (>= 0.6.3)
38 | rails-dom-testing (~> 2.2)
39 | rails-html-sanitizer (~> 1.6)
40 | actiontext (7.1.2)
41 | actionpack (= 7.1.2)
42 | activerecord (= 7.1.2)
43 | activestorage (= 7.1.2)
44 | activesupport (= 7.1.2)
45 | globalid (>= 0.6.0)
46 | nokogiri (>= 1.8.5)
47 | actionview (7.1.2)
48 | activesupport (= 7.1.2)
49 | builder (~> 3.1)
50 | erubi (~> 1.11)
51 | rails-dom-testing (~> 2.2)
52 | rails-html-sanitizer (~> 1.6)
53 | activejob (7.1.2)
54 | activesupport (= 7.1.2)
55 | globalid (>= 0.3.6)
56 | activemodel (7.1.2)
57 | activesupport (= 7.1.2)
58 | activerecord (7.1.2)
59 | activemodel (= 7.1.2)
60 | activesupport (= 7.1.2)
61 | timeout (>= 0.4.0)
62 | activestorage (7.1.2)
63 | actionpack (= 7.1.2)
64 | activejob (= 7.1.2)
65 | activerecord (= 7.1.2)
66 | activesupport (= 7.1.2)
67 | marcel (~> 1.0)
68 | activesupport (7.1.2)
69 | base64
70 | bigdecimal
71 | concurrent-ruby (~> 1.0, >= 1.0.2)
72 | connection_pool (>= 2.2.5)
73 | drb
74 | i18n (>= 1.6, < 2)
75 | minitest (>= 5.1)
76 | mutex_m
77 | tzinfo (~> 2.0)
78 | addressable (2.8.6)
79 | public_suffix (>= 2.0.2, < 6.0)
80 | base64 (0.2.0)
81 | bigdecimal (3.1.5)
82 | bindex (0.8.1)
83 | bootsnap (1.17.0)
84 | msgpack (~> 1.2)
85 | builder (3.2.4)
86 | capybara (3.39.2)
87 | addressable
88 | matrix
89 | mini_mime (>= 0.1.3)
90 | nokogiri (~> 1.8)
91 | rack (>= 1.6.0)
92 | rack-test (>= 0.6.3)
93 | regexp_parser (>= 1.5, < 3.0)
94 | xpath (~> 3.2)
95 | concurrent-ruby (1.2.2)
96 | connection_pool (2.4.1)
97 | crass (1.0.6)
98 | date (3.3.4)
99 | debug (1.9.0)
100 | irb (~> 1.10)
101 | reline (>= 0.3.8)
102 | drb (2.2.0)
103 | ruby2_keywords
104 | erubi (1.12.0)
105 | globalid (1.2.1)
106 | activesupport (>= 6.1)
107 | i18n (1.14.1)
108 | concurrent-ruby (~> 1.0)
109 | importmap-rails (1.2.3)
110 | actionpack (>= 6.0.0)
111 | activesupport (>= 6.0.0)
112 | railties (>= 6.0.0)
113 | io-console (0.7.1)
114 | irb (1.11.0)
115 | rdoc
116 | reline (>= 0.3.8)
117 | jbuilder (2.11.5)
118 | actionview (>= 5.0.0)
119 | activesupport (>= 5.0.0)
120 | loofah (2.22.0)
121 | crass (~> 1.0.2)
122 | nokogiri (>= 1.12.0)
123 | mail (2.8.1)
124 | mini_mime (>= 0.1.1)
125 | net-imap
126 | net-pop
127 | net-smtp
128 | marcel (1.0.2)
129 | matrix (0.4.2)
130 | mini_mime (1.1.5)
131 | minitest (5.20.0)
132 | msgpack (1.7.2)
133 | mutex_m (0.2.0)
134 | net-imap (0.4.8)
135 | date
136 | net-protocol
137 | net-pop (0.1.2)
138 | net-protocol
139 | net-protocol (0.2.2)
140 | timeout
141 | net-smtp (0.4.0)
142 | net-protocol
143 | nio4r (2.7.0)
144 | nokogiri (1.15.5-aarch64-linux)
145 | racc (~> 1.4)
146 | nokogiri (1.15.5-arm-linux)
147 | racc (~> 1.4)
148 | nokogiri (1.15.5-arm64-darwin)
149 | racc (~> 1.4)
150 | nokogiri (1.15.5-x86-linux)
151 | racc (~> 1.4)
152 | nokogiri (1.15.5-x86_64-darwin)
153 | racc (~> 1.4)
154 | nokogiri (1.15.5-x86_64-linux)
155 | racc (~> 1.4)
156 | psych (5.1.2)
157 | stringio
158 | public_suffix (5.0.4)
159 | puma (6.4.0)
160 | nio4r (~> 2.0)
161 | racc (1.7.3)
162 | rack (3.0.8)
163 | rack-session (2.0.0)
164 | rack (>= 3.0.0)
165 | rack-test (2.1.0)
166 | rack (>= 1.3)
167 | rackup (2.1.0)
168 | rack (>= 3)
169 | webrick (~> 1.8)
170 | rails (7.1.2)
171 | actioncable (= 7.1.2)
172 | actionmailbox (= 7.1.2)
173 | actionmailer (= 7.1.2)
174 | actionpack (= 7.1.2)
175 | actiontext (= 7.1.2)
176 | actionview (= 7.1.2)
177 | activejob (= 7.1.2)
178 | activemodel (= 7.1.2)
179 | activerecord (= 7.1.2)
180 | activestorage (= 7.1.2)
181 | activesupport (= 7.1.2)
182 | bundler (>= 1.15.0)
183 | railties (= 7.1.2)
184 | rails-dom-testing (2.2.0)
185 | activesupport (>= 5.0.0)
186 | minitest
187 | nokogiri (>= 1.6)
188 | rails-html-sanitizer (1.6.0)
189 | loofah (~> 2.21)
190 | nokogiri (~> 1.14)
191 | railties (7.1.2)
192 | actionpack (= 7.1.2)
193 | activesupport (= 7.1.2)
194 | irb
195 | rackup (>= 1.0.0)
196 | rake (>= 12.2)
197 | thor (~> 1.0, >= 1.2.2)
198 | zeitwerk (~> 2.6)
199 | rake (13.1.0)
200 | rdoc (6.6.2)
201 | psych (>= 4.0.0)
202 | regexp_parser (2.8.3)
203 | reline (0.4.1)
204 | io-console (~> 0.5)
205 | rexml (3.2.6)
206 | ruby2_keywords (0.0.5)
207 | rubyzip (2.3.2)
208 | selenium-webdriver (4.16.0)
209 | rexml (~> 3.2, >= 3.2.5)
210 | rubyzip (>= 1.2.2, < 3.0)
211 | websocket (~> 1.0)
212 | simple_form (5.3.0)
213 | actionpack (>= 5.2)
214 | activemodel (>= 5.2)
215 | sprockets (4.2.1)
216 | concurrent-ruby (~> 1.0)
217 | rack (>= 2.2.4, < 4)
218 | sprockets-rails (3.4.2)
219 | actionpack (>= 5.2)
220 | activesupport (>= 5.2)
221 | sprockets (>= 3.0.0)
222 | sqlite3 (1.6.9-aarch64-linux)
223 | sqlite3 (1.6.9-arm-linux)
224 | sqlite3 (1.6.9-arm64-darwin)
225 | sqlite3 (1.6.9-x86-linux)
226 | sqlite3 (1.6.9-x86_64-darwin)
227 | sqlite3 (1.6.9-x86_64-linux)
228 | stimulus-rails (1.3.0)
229 | railties (>= 6.0.0)
230 | stringio (3.1.0)
231 | tailwindcss-rails (2.1.0)
232 | railties (>= 6.0.0)
233 | tailwindcss-rails (2.1.0-aarch64-linux)
234 | railties (>= 6.0.0)
235 | tailwindcss-rails (2.1.0-arm-linux)
236 | railties (>= 6.0.0)
237 | tailwindcss-rails (2.1.0-arm64-darwin)
238 | railties (>= 6.0.0)
239 | tailwindcss-rails (2.1.0-x86_64-darwin)
240 | railties (>= 6.0.0)
241 | tailwindcss-rails (2.1.0-x86_64-linux)
242 | railties (>= 6.0.0)
243 | thor (1.3.0)
244 | timeout (0.4.1)
245 | turbo-rails (1.5.0)
246 | actionpack (>= 6.0.0)
247 | activejob (>= 6.0.0)
248 | railties (>= 6.0.0)
249 | tzinfo (2.0.6)
250 | concurrent-ruby (~> 1.0)
251 | web-console (4.2.1)
252 | actionview (>= 6.0.0)
253 | activemodel (>= 6.0.0)
254 | bindex (>= 0.4.0)
255 | railties (>= 6.0.0)
256 | webrick (1.8.1)
257 | websocket (1.2.10)
258 | websocket-driver (0.7.6)
259 | websocket-extensions (>= 0.1.0)
260 | websocket-extensions (0.1.5)
261 | xpath (3.2.0)
262 | nokogiri (~> 1.8)
263 | zeitwerk (2.6.12)
264 |
265 | PLATFORMS
266 | aarch64-linux
267 | arm-linux
268 | arm64-darwin
269 | x86-linux
270 | x86_64-darwin
271 | x86_64-linux
272 |
273 | DEPENDENCIES
274 | bootsnap
275 | capybara
276 | debug
277 | importmap-rails
278 | jbuilder
279 | puma (>= 5.0)
280 | rails (~> 7.1.2)
281 | selenium-webdriver
282 | simple_form
283 | sprockets-rails
284 | sqlite3 (~> 1.4)
285 | stimulus-rails
286 | tailwindcss-rails
287 | turbo-rails
288 | tzinfo-data
289 | web-console
290 |
291 | RUBY VERSION
292 | ruby 3.2.2p53
293 |
294 | BUNDLED WITH
295 | 2.5.2
296 |
--------------------------------------------------------------------------------
/Procfile.dev:
--------------------------------------------------------------------------------
1 | web: env RUBY_DEBUG_OPEN=true bin/rails server -p 3000
2 | css: bin/rails tailwindcss:watch
3 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Invisible Commerce Rails Frontend Test
2 |
3 | Thank you for applying to Invisible Commerce! This is a small test to help us get a sense of your skills and how you approach problems.
4 |
5 | ## The Task
6 |
7 | We have a simple Rails app that allows editing of custom "Return Reasons". We'd like you to take the [Figma design](https://www.figma.com/file/ZrgctOIZqB7CMDZwkKcQrs/Front-Engineer-Exercise?type=design&node-id=1%3A384&mode=dev) and implement it in the app.
8 |
9 | This involves a few things:
10 | 1. Update the application layout to match the design (using Tailwind CSS, already included in the app)
11 | 2. Update the page template to match the design (`app/views/storefronts/edit.html.erb`)
12 | 3. Move the nested form for each Reason into a modal, and update the design to match
13 | 4. Enable drag-and-drop reordering of the Reasons
14 |
15 | ## Getting Started
16 |
17 | We are using Ruby 3.2.2 and Rails 7.1.2 in this project. Make sure your environment is set up to match.
18 |
19 | 1. Fork this repo and clone it locally
20 | 2. Run `bundle install`
21 | 3. Run `./bin/dev`
22 | 4. Visit `http://localhost:3000/` (which will point to `/storefronts/1/edit`)
23 |
24 | The included SQLite database has been pre-populated a single Storefront with 7 Reasons, which matches the Figma design.
25 | You can add more Reasons by clicking the "Add Reason" button and then saving or delete them by clicking the "Remove" button and saving.
26 |
27 | ## Notes
28 |
29 | - For the forms, we are using `simple_form` gem and there is an included `simple_form_tailwind.rb` initializer that you can use to customize the markup
30 | - There is already a `modal` Stimulus controller included in the app, which you can use to implement the modal form
31 | - For CSS portions, you are required to use Tailwind CSS
32 | - For JS portions, you are required to use Stimulus/Hotwire/Turbo
33 | - We will be evaluating your work based on the quality of the code, the accuracy of the implementation, and the attention to detail in the design
34 | - We will also be evaluating the "Railsyness" of your code, so please try to stick to the idioms and conventions of the framework
35 |
36 | ## Submitting Your Work
37 |
38 | When you're done, please send us a link to your fork of this repo.
39 |
--------------------------------------------------------------------------------
/Rakefile:
--------------------------------------------------------------------------------
1 | # Add your own tasks in files placed in lib/tasks ending in .rake,
2 | # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
3 |
4 | require_relative "config/application"
5 |
6 | Rails.application.load_tasks
7 |
--------------------------------------------------------------------------------
/app/assets/builds/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/abbasikov/Rails-frontend-test/0497c2ac2853f300ba20419e89a96a08cc686c9a/app/assets/builds/.keep
--------------------------------------------------------------------------------
/app/assets/config/manifest.js:
--------------------------------------------------------------------------------
1 | //= link_tree ../images
2 | //= link_directory ../stylesheets .css
3 | //= link_tree ../../javascript .js
4 | //= link_tree ../../../vendor/javascript .js
5 | //= link_tree ../builds
6 |
--------------------------------------------------------------------------------
/app/assets/images/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/abbasikov/Rails-frontend-test/0497c2ac2853f300ba20419e89a96a08cc686c9a/app/assets/images/.keep
--------------------------------------------------------------------------------
/app/assets/images/dotsIcon.svg:
--------------------------------------------------------------------------------
1 |
13 |
--------------------------------------------------------------------------------
/app/assets/images/eye-off.svg:
--------------------------------------------------------------------------------
1 |
12 |
--------------------------------------------------------------------------------
/app/assets/images/eye.svg:
--------------------------------------------------------------------------------
1 |
7 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/application.css:
--------------------------------------------------------------------------------
1 | /*
2 | * This is a manifest file that'll be compiled into application.css, which will include all the files
3 | * listed below.
4 | *
5 | * Any CSS (and SCSS, if configured) file within this directory, lib/assets/stylesheets, or any plugin's
6 | * vendor/assets/stylesheets directory can be referenced here using a relative path.
7 | *
8 | * You're free to add application-wide styles to this file and they'll appear at the bottom of the
9 | * compiled file so the styles you add here take precedence over styles defined in any other CSS
10 | * files in this directory. Styles in this file should be added after the last require_* statement.
11 | * It is generally better to create a new file per style scope.
12 | *
13 | *= require_tree .
14 | *= require_self
15 | */
16 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/application.tailwind.css:
--------------------------------------------------------------------------------
1 | @tailwind base;
2 | @tailwind components;
3 | @tailwind utilities;
4 |
5 | @layer utilities {
6 | body {
7 | @apply bg-black;
8 | }
9 | }
10 |
11 | @layer components {
12 | .btn-primary {
13 | @apply py-2 px-4 bg-yellow-400;
14 | }
15 | .btn {
16 | @apply py-2 px-4 bg-gray-200;
17 | }
18 | .btn-danger {
19 | @apply py-2 px-4 bg-red-200;
20 | }
21 | }
22 |
23 | .h1 {
24 | @apply font-semibold text-2xl;
25 | }
26 |
27 | .home {
28 | @apply shadow-md border-2 border-red-500;
29 | }
30 |
31 | .footer {
32 | width: calc(100% - 250px);
33 | @apply fixed bottom-0 right-0 bg-white p-2 md:p-4 flex items-center justify-between shadow;
34 | }
35 |
36 | .footer .p {
37 | @apply text-base font-medium;
38 | }
39 | .footer .btn {
40 | background:rgba(255, 201, 51, 1);
41 | padding:14px, 24px, 14px, 24px;
42 | border-radius:8px;
43 | -webkit-border-radius:8px;
44 | -moz-border-radius:8px;
45 | -ms-border-radius:8px;
46 | -o-border-radius:8px;
47 | }
48 |
49 | .text {
50 | color: var(--Secondary-Main, #3164F6);
51 | font-family: Inter;
52 | font-size: 16px;
53 | font-style: normal;
54 | font-weight: 600;
55 | line-height: 140%; /* 22.4px */
56 | }
57 |
58 |
59 | .ul{
60 | background-color: #F8F8FB;
61 | border:1px solid #E3E3E3;
62 | border-radius: 8px;
63 | -webkit-border-radius: 8px;
64 | -moz-border-radius: 8px;
65 | -ms-border-radius: 8px;
66 | -o-border-radius: 8px;
67 | }
68 |
69 | .list {
70 | border-top: 1px solid #E3E3E3;
71 | background-color: #F8F8FB;
72 | border-bottom-left-radius: 8px;
73 | border-bottom-right-radius: 8px;
74 | }
75 |
76 | .modal{
77 | display: flex;
78 | align-items: center;
79 | justify-content: space-between;
80 | padding: 8px 0px;
81 | border-bottom: 1px solid rgba(227, 230, 232, 1);
82 | }
83 | .modalHeading{
84 | color: var(--Secondary-Main, black);
85 | font-family: Inter;
86 | font-size: 24px;
87 | font-style: normal;
88 | font-weight: 600;
89 | }
90 |
91 | .hint{
92 | color: var(--Neutral-Dark-Grey, #292929);
93 | font-family: Inter;
94 | font-size: 14px;
95 | font-style: normal;
96 | font-weight: 400;
97 | line-height: 140%; /* 19.6px */
98 | letter-spacing: -0.154px;
99 | margin-top: -10px;
100 | margin-bottom: 20px;
101 | max-width: 544px;
102 | }
103 |
104 | .eyeBox{
105 | display: flex;
106 | align-items: center;
107 | margin-bottom: 10px;
108 | margin-top: 10px;
109 | }
110 |
111 | .eyeText{
112 | color: var(--Neutral-Dark-Grey, #292929);
113 | /* Body Large/Semi Bold */
114 | font-family: Inter;
115 | font-size: 16px;
116 | font-style: normal;
117 | font-weight: 600;
118 | line-height: 140%;
119 | }
120 |
121 | .eyeHint{
122 | margin-left: 30px;
123 | }
124 |
125 | .dashboard-form-fields{
126 | margin-top: 20px;
127 | }
128 |
129 |
130 | .continue{
131 | border-radius: 8px;
132 | background: #FFC933;
133 | display: flex;
134 | width: 95px;
135 | padding: 8px 24px;
136 | justify-content: center;
137 | align-items: center;
138 | gap: 4px;
139 | }
140 |
141 | .remove{
142 | display: flex;
143 | width: 95px;
144 | padding: 8px 24px;
145 | justify-content: center;
146 | align-items: center;
147 | gap: 4px;
148 | border-radius: 8px;
149 | border: 2px solid var(--Additional-Error, #EB4747);
150 | color:#EB4747;
151 | -webkit-border-radius: 8px;
152 | -moz-border-radius: 8px;
153 | -ms-border-radius: 8px;
154 | -o-border-radius: 8px;
155 | }
156 |
157 | .buttonDiv{
158 | display: flex;
159 | align-items: center;
160 | justify-content: space-between;
161 | padding: 8px 0px;
162 | }
163 |
164 | .mainDiv{
165 | max-width: 750px;
166 | margin: auto;
167 | }
168 |
169 | .edit{
170 | color: var(--Secondary-Main, #3164F6);
171 | /* Body Large/Semi Bold */
172 | font-family: Inter;
173 | font-size: 16px;
174 | font-style: normal;
175 | font-weight: 600;
176 | }
177 |
178 | .abbr:where([title]){
179 | display: none !important;
180 | }
181 |
182 |
183 | abbr{
184 | display:none !important;
185 | }
--------------------------------------------------------------------------------
/app/controllers/application_controller.rb:
--------------------------------------------------------------------------------
1 | class ApplicationController < ActionController::Base
2 | end
3 |
--------------------------------------------------------------------------------
/app/controllers/concerns/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/abbasikov/Rails-frontend-test/0497c2ac2853f300ba20419e89a96a08cc686c9a/app/controllers/concerns/.keep
--------------------------------------------------------------------------------
/app/controllers/reasons_controller.rb:
--------------------------------------------------------------------------------
1 | class ReasonsController < ApplicationController
2 | before_action :set_reason, only: %i[update_order show]
3 |
4 | def update_order
5 | @reason.insert_at(params[:ordering].to_i) if @reason.present?
6 | end
7 |
8 | def show
9 | render json: @reason
10 | rescue ActiveRecord::RecordNotFound
11 | render json: { error: 'Reason not found' }, status: :not_found
12 | end
13 |
14 | private
15 |
16 | def set_reason
17 | @reason = Reason.find(params[:id])
18 | end
19 | end
--------------------------------------------------------------------------------
/app/controllers/storefronts_controller.rb:
--------------------------------------------------------------------------------
1 | class StorefrontsController < ApplicationController
2 | before_action :set_storefront, only: %i[ show edit update destroy ]
3 |
4 | # GET /storefronts or /storefronts.json
5 | def index
6 | @storefronts = Storefront.all
7 | end
8 |
9 | # GET /storefronts/1 or /storefronts/1.json
10 | def show
11 | end
12 |
13 | # GET /storefronts/new
14 | def new
15 | @storefront = Storefront.new
16 | end
17 |
18 | # GET /storefronts/1/edit
19 | def edit
20 | end
21 |
22 | # POST /storefronts or /storefronts.json
23 | def create
24 | @storefront = Storefront.new(storefront_params)
25 |
26 | respond_to do |format|
27 | if @storefront.save
28 | format.html { redirect_to storefront_url(@storefront), notice: "Storefront was successfully created." }
29 | format.json { render :show, status: :created, location: @storefront }
30 | else
31 | format.html { render :new, status: :unprocessable_entity }
32 | format.json { render json: @storefront.errors, status: :unprocessable_entity }
33 | end
34 | end
35 | end
36 |
37 | # PATCH/PUT /storefronts/1 or /storefronts/1.json
38 | def update
39 | respond_to do |format|
40 | if @storefront.update(storefront_params)
41 | format.html { redirect_to [:edit, @storefront], notice: "Storefront was successfully updated." }
42 | format.json { render :edit, status: :ok, location: @storefront }
43 | else
44 | format.html { render :edit, status: :unprocessable_entity }
45 | format.json { render json: @storefront.errors, status: :unprocessable_entity }
46 | end
47 | end
48 | end
49 |
50 | # DELETE /storefronts/1 or /storefronts/1.json
51 | def destroy
52 | @storefront.destroy!
53 |
54 | respond_to do |format|
55 | format.html { redirect_to storefronts_url, notice: "Storefront was successfully destroyed." }
56 | format.json { head :no_content }
57 | end
58 | end
59 |
60 | private
61 | # Use callbacks to share common setup or constraints between actions.
62 | def set_storefront
63 | @storefront = Storefront.find(params[:id])
64 | @reasons = @storefront.reasons.ordered
65 | end
66 |
67 | # Only allow a list of trusted parameters through.
68 | def storefront_params
69 | params.fetch(:storefront, {}).permit(
70 | :name,
71 | {
72 | reasons_attributes: [
73 | :id,
74 | :code,
75 | :label,
76 | :ordering,
77 | :active,
78 | :_destroy,
79 | { restricted_resolution_types: [] }
80 | ]
81 | }
82 | )
83 | end
84 | end
85 |
--------------------------------------------------------------------------------
/app/helpers/application_helper.rb:
--------------------------------------------------------------------------------
1 | module ApplicationHelper
2 | end
3 |
--------------------------------------------------------------------------------
/app/helpers/storefronts_helper.rb:
--------------------------------------------------------------------------------
1 | module StorefrontsHelper
2 | end
3 |
--------------------------------------------------------------------------------
/app/javascript/application.js:
--------------------------------------------------------------------------------
1 | // Configure your import map in config/importmap.rb. Read more: https://github.com/rails/importmap-rails
2 | import "@hotwired/turbo-rails"
3 | import "controllers"
4 |
--------------------------------------------------------------------------------
/app/javascript/controllers/application.js:
--------------------------------------------------------------------------------
1 | import { Application } from "@hotwired/stimulus"
2 |
3 | const application = Application.start()
4 |
5 | // Configure Stimulus development experience
6 | application.debug = false
7 | window.Stimulus = application
8 |
9 | export { application }
10 |
--------------------------------------------------------------------------------
/app/javascript/controllers/drag_controller.js:
--------------------------------------------------------------------------------
1 | import { Controller } from "@hotwired/stimulus"
2 | import $ from "jquery";
3 | import Sortable from "sortablejs"
4 |
5 | export default class extends Controller {
6 | connect() {
7 | this.sortable = Sortable.create(this.element, {
8 | onEnd: this.end.bind(this)
9 | })
10 | }
11 | end(event){
12 | let id = event.item.dataset.id
13 | $.ajax({
14 | headers: {
15 | "X-CSRF-Token": $('meta[name="csrf-token"]').attr("content"),
16 | },
17 | url: "/reasons/"+id+"/update_order",
18 | type: 'PATCH',
19 | dataType: "json",
20 | data: {
21 | ordering: event.newIndex + 1
22 | },
23 | });
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/app/javascript/controllers/index.js:
--------------------------------------------------------------------------------
1 | // Import and register all your controllers from the importmap under controllers/*
2 |
3 | import { application } from "controllers/application"
4 |
5 | // Eager load all controllers defined in the import map under controllers/**/*_controller
6 | import { eagerLoadControllersFrom } from "@hotwired/stimulus-loading"
7 | eagerLoadControllersFrom("controllers", application)
8 |
9 | // Lazy load controllers as they appear in the DOM (remember not to preload controllers in import map!)
10 | // import { lazyLoadControllersFrom } from "@hotwired/stimulus-loading"
11 | // lazyLoadControllersFrom("controllers", application)
12 |
--------------------------------------------------------------------------------
/app/javascript/controllers/modal_controller.js:
--------------------------------------------------------------------------------
1 | import { Controller } from "@hotwired/stimulus"
2 | import $ from "jquery";
3 |
4 | export default class extends Controller {
5 | static targets = [
6 | 'modal'
7 | ]
8 |
9 | async show(e) {
10 | e.preventDefault()
11 | const modalId = e.target.getAttribute("data-modal-id");
12 | const modal = document.getElementById(modalId);
13 | const reasonId = e.currentTarget.dataset.id
14 | modal.classList.remove("hidden");
15 | modal.setAttribute("aria-hidden", "false");
16 | const reasonDetails = await this.fetchReasonDetails(reasonId);
17 | this.updateModalContent(modalId, reasonDetails);
18 | }
19 |
20 | async fetchReasonDetails(reasonId) {
21 | let res;
22 | try {
23 | await $.ajax({
24 | headers: {
25 | "X-CSRF-Token": $('meta[name="csrf-token"]').attr("content"),
26 | },
27 | url: "/reasons/"+reasonId,
28 | type: 'GET',
29 | dataType: "json",
30 | data: {
31 | id: reasonId
32 | },
33 | success: function(response){
34 | res = response
35 | },
36 | });
37 | } catch (error) {
38 | console.error(error);
39 | window.alert(error);
40 | }
41 | return res;
42 | }
43 |
44 | updateModalContent(modalId, reasonDetails) {
45 | const modal = document.getElementById(modalId);
46 | modal.querySelector('input[name="storefront[reasons_attributes][0][label]"]').value = reasonDetails.label;
47 | modal.querySelector('input[name="storefront[reasons_attributes][0][code]"]').value = reasonDetails.code;
48 | }
49 |
50 | hide(e) {
51 | e.preventDefault()
52 | const modalId = e.target.getAttribute("data-modal-id");
53 | const modal = document.getElementById(modalId);
54 | modal.classList.add("hidden");
55 | modal.setAttribute("aria-hidden", "true")
56 | }
57 | }
--------------------------------------------------------------------------------
/app/javascript/controllers/nested_form_controller.js:
--------------------------------------------------------------------------------
1 | import { Controller } from "@hotwired/stimulus"
2 |
3 | export default class extends Controller {
4 | static targets = ["addItem", "template"]
5 | static values = { index: String }
6 |
7 | addAssociation(event) {
8 | console.log('addAssociation')
9 | event.preventDefault()
10 | console.log(this.indexValue);
11 | const child_index_name = this.indexValue
12 | const content = this.templateTarget.innerHTML.replace(new RegExp(child_index_name, "g"), new Date().valueOf())
13 | this.addItemTarget.insertAdjacentHTML('beforebegin', content)
14 | }
15 |
16 | removeAssociation(event, isRemoveBundle) {
17 | let item = event
18 | if (!isRemoveBundle) {
19 | event.preventDefault()
20 | item = event.target.closest(".nested-form-wrapper")
21 | }
22 | const isBundleItem = item.getAttribute('data-bundle-item')
23 | const orderClass = this.getInputClass(isBundleItem, isRemoveBundle)
24 | this.destroyInput(item, orderClass)
25 | if (!isRemoveBundle && isBundleItem) {
26 | this.checkBundle(event)
27 | }
28 | }
29 | getInputClass(isBundleItem, isRemoveBundle) {
30 | return isBundleItem ? '.bundle-destroy' : isRemoveBundle ? '.order-destroy' : ''
31 | }
32 | destroyInput(item, orderClass) {
33 | const destroyInput = item.querySelector(`input${orderClass}[name*='_destroy']`);
34 | destroyInput.value = 1;
35 | this.clearRequired(item);
36 | item.style.display = 'none';
37 | }
38 | clearRequired(item) {
39 | item.querySelectorAll("input[required]").forEach((node) => {
40 | node.required = false
41 | })
42 | item.querySelectorAll("select[required]").forEach((node) => {
43 | node.required = false
44 | })
45 | }
46 |
47 | checkBundle(event) {
48 | event.preventDefault()
49 | const itemWrap = event.target.closest('.bundle-items')
50 | let hasItem = false
51 | itemWrap.querySelectorAll('.bundle-item').forEach(item => {
52 | if (item.style.display != 'none')
53 | hasItem = true
54 | })
55 | if (!hasItem) {
56 | const removeItem = itemWrap.closest('.rma-item-wrap').querySelector('.nested-form-wrapper')
57 | this.removeAssociation(removeItem, true)
58 | }
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/app/models/application_record.rb:
--------------------------------------------------------------------------------
1 | class ApplicationRecord < ActiveRecord::Base
2 | primary_abstract_class
3 | end
4 |
--------------------------------------------------------------------------------
/app/models/concerns/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/abbasikov/Rails-frontend-test/0497c2ac2853f300ba20419e89a96a08cc686c9a/app/models/concerns/.keep
--------------------------------------------------------------------------------
/app/models/reason.rb:
--------------------------------------------------------------------------------
1 | class Reason < ApplicationRecord
2 | acts_as_list column: :ordering
3 | belongs_to :storefront
4 |
5 | validates :code, presence: true, uniqueness: { scope: :storefront_id }
6 | validates :label, presence: true
7 |
8 | scope :ordered, -> { order(ordering: :asc) }
9 | end
10 |
--------------------------------------------------------------------------------
/app/models/storefront.rb:
--------------------------------------------------------------------------------
1 | class Storefront < ApplicationRecord
2 | validates :name, presence: true, uniqueness: true
3 |
4 | has_many :reasons, inverse_of: :storefront, dependent: :destroy
5 |
6 | accepts_nested_attributes_for :reasons, reject_if: proc { |attributes|
7 | attributes['code'].blank? || attributes['label'].blank?
8 | }, allow_destroy: true
9 | end
10 |
--------------------------------------------------------------------------------
/app/views/layouts/application.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | RailsFrontendTest
5 |
6 | <%= csrf_meta_tags %>
7 | <%= csp_meta_tag %>
8 |
9 |
10 |
11 |
12 | <%= stylesheet_link_tag "tailwind", "inter-font", "data-turbo-track": "reload" %>
13 | <%= stylesheet_link_tag "application", "data-turbo-track": "reload" %>
14 | <%= javascript_importmap_tags %>
15 |
16 |
17 |
18 |
19 |
20 |
21 | <%= yield %>
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/app/views/storefronts/_form.html.erb:
--------------------------------------------------------------------------------
1 |
2 | <%= simple_form_for storefront, data: { controller: 'nested-form', nested_form_index_value: 'NEW_RECORD' } do |form| %>
3 | <% if storefront.errors.any? %>
4 |
5 |
<%= pluralize(storefront.errors.count, "error") %> prohibited this storefront from being saved:
6 |
7 | <% storefront.errors.each do |error| %>
8 | - <%= error.full_message %>
9 | <% end %>
10 |
11 |
12 | <% end %>
13 |
14 |
15 |
16 |
17 | <%= form.simple_fields_for :reasons, Reason.new, child_index: 'NEW_RECORD' do |reason_fields| %>
18 | <%= render 'reason', f: reason_fields %>
19 | <% end %>
20 |
21 |
22 |
23 |
24 |
25 |
28 |
29 |
30 | <% @reasons.each do |item| %>
31 |
32 |
33 |
34 |
 %>)
35 |
 %>)
36 | <%= item.label %>
37 |
38 |
39 |
40 | <% end %>
41 |
42 |
43 |
44 |
45 |
46 |
47 |
55 |
56 |
57 | <%= form.simple_fields_for :reasons, Reason.new do |reason_fields| %>
58 | <%= render 'reason', f: reason_fields %>
59 | <% end %>
60 |
61 |
62 | <% end %>
63 |
64 |
--------------------------------------------------------------------------------
/app/views/storefronts/_reason.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
Edit Return Reason
4 |
5 |
6 |
39 |
40 |
--------------------------------------------------------------------------------
/app/views/storefronts/_storefront.html.erb:
--------------------------------------------------------------------------------
1 |
2 | <%= link_to storefront.name, [:edit, storefront] %>
3 |
4 |
--------------------------------------------------------------------------------
/app/views/storefronts/_storefront.json.jbuilder:
--------------------------------------------------------------------------------
1 | json.extract! storefront, :id, :created_at, :updated_at
2 | json.url storefront_url(storefront, format: :json)
3 |
--------------------------------------------------------------------------------
/app/views/storefronts/edit.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
Returns
4 |
5 |
6 |
7 |
13 |
14 |
15 |
16 | <%= render "form", storefront: @storefront %>
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/app/views/storefronts/index.html.erb:
--------------------------------------------------------------------------------
1 |
2 | <% if notice.present? %>
3 |
<%= notice %>
4 | <% end %>
5 |
6 |
7 |
Storefronts
8 | <%= link_to "New storefront", new_storefront_path, class: "rounded-lg py-3 px-5 bg-blue-600 text-white block font-medium" %>
9 |
10 |
11 |
12 | <%= render @storefronts %>
13 |
14 |
15 |
--------------------------------------------------------------------------------
/app/views/storefronts/index.json.jbuilder:
--------------------------------------------------------------------------------
1 | json.array! @storefronts, partial: "storefronts/storefront", as: :storefront
2 |
--------------------------------------------------------------------------------
/app/views/storefronts/new.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
New storefront
3 |
4 | <%= render "form", storefront: @storefront %>
5 |
6 | <%= link_to "Back to storefronts", storefronts_path, class: "ml-2 rounded-lg py-3 px-5 bg-gray-100 inline-block font-medium" %>
7 |
8 |
--------------------------------------------------------------------------------
/app/views/storefronts/show.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 | <% if notice.present? %>
4 |
<%= notice %>
5 | <% end %>
6 |
7 | <%= render @storefront %>
8 |
9 | <%= link_to "Edit this storefront", edit_storefront_path(@storefront), class: "mt-2 rounded-lg py-3 px-5 bg-gray-100 inline-block font-medium" %>
10 |
11 | <%= button_to "Destroy this storefront", storefront_path(@storefront), method: :delete, class: "mt-2 rounded-lg py-3 px-5 bg-gray-100 font-medium" %>
12 |
13 | <%= link_to "Back to storefronts", storefronts_path, class: "ml-2 rounded-lg py-3 px-5 bg-gray-100 inline-block font-medium" %>
14 |
15 |
16 |
--------------------------------------------------------------------------------
/app/views/storefronts/show.json.jbuilder:
--------------------------------------------------------------------------------
1 | json.partial! "storefronts/storefront", storefront: @storefront
2 |
--------------------------------------------------------------------------------
/bin/bundle:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | # frozen_string_literal: true
3 |
4 | #
5 | # This file was generated by Bundler.
6 | #
7 | # The application 'bundle' is installed as part of a gem, and
8 | # this file is here to facilitate running it.
9 | #
10 |
11 | require "rubygems"
12 |
13 | m = Module.new do
14 | module_function
15 |
16 | def invoked_as_script?
17 | File.expand_path($0) == File.expand_path(__FILE__)
18 | end
19 |
20 | def env_var_version
21 | ENV["BUNDLER_VERSION"]
22 | end
23 |
24 | def cli_arg_version
25 | return unless invoked_as_script? # don't want to hijack other binstubs
26 | return unless "update".start_with?(ARGV.first || " ") # must be running `bundle update`
27 | bundler_version = nil
28 | update_index = nil
29 | ARGV.each_with_index do |a, i|
30 | if update_index && update_index.succ == i && a.match?(Gem::Version::ANCHORED_VERSION_PATTERN)
31 | bundler_version = a
32 | end
33 | next unless a =~ /\A--bundler(?:[= ](#{Gem::Version::VERSION_PATTERN}))?\z/
34 | bundler_version = $1
35 | update_index = i
36 | end
37 | bundler_version
38 | end
39 |
40 | def gemfile
41 | gemfile = ENV["BUNDLE_GEMFILE"]
42 | return gemfile if gemfile && !gemfile.empty?
43 |
44 | File.expand_path("../Gemfile", __dir__)
45 | end
46 |
47 | def lockfile
48 | lockfile =
49 | case File.basename(gemfile)
50 | when "gems.rb" then gemfile.sub(/\.rb$/, ".locked")
51 | else "#{gemfile}.lock"
52 | end
53 | File.expand_path(lockfile)
54 | end
55 |
56 | def lockfile_version
57 | return unless File.file?(lockfile)
58 | lockfile_contents = File.read(lockfile)
59 | return unless lockfile_contents =~ /\n\nBUNDLED WITH\n\s{2,}(#{Gem::Version::VERSION_PATTERN})\n/
60 | Regexp.last_match(1)
61 | end
62 |
63 | def bundler_requirement
64 | @bundler_requirement ||=
65 | env_var_version ||
66 | cli_arg_version ||
67 | bundler_requirement_for(lockfile_version)
68 | end
69 |
70 | def bundler_requirement_for(version)
71 | return "#{Gem::Requirement.default}.a" unless version
72 |
73 | bundler_gem_version = Gem::Version.new(version)
74 |
75 | bundler_gem_version.approximate_recommendation
76 | end
77 |
78 | def load_bundler!
79 | ENV["BUNDLE_GEMFILE"] ||= gemfile
80 |
81 | activate_bundler
82 | end
83 |
84 | def activate_bundler
85 | gem_error = activation_error_handling do
86 | gem "bundler", bundler_requirement
87 | end
88 | return if gem_error.nil?
89 | require_error = activation_error_handling do
90 | require "bundler/version"
91 | end
92 | return if require_error.nil? && Gem::Requirement.new(bundler_requirement).satisfied_by?(Gem::Version.new(Bundler::VERSION))
93 | warn "Activating bundler (#{bundler_requirement}) failed:\n#{gem_error.message}\n\nTo install the version of bundler this project requires, run `gem install bundler -v '#{bundler_requirement}'`"
94 | exit 42
95 | end
96 |
97 | def activation_error_handling
98 | yield
99 | nil
100 | rescue StandardError, LoadError => e
101 | e
102 | end
103 | end
104 |
105 | m.load_bundler!
106 |
107 | if m.invoked_as_script?
108 | load Gem.bin_path("bundler", "bundle")
109 | end
110 |
--------------------------------------------------------------------------------
/bin/dev:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | if ! gem list foreman -i --silent; then
4 | echo "Installing foreman..."
5 | gem install foreman
6 | fi
7 |
8 | exec foreman start -f Procfile.dev "$@"
9 |
--------------------------------------------------------------------------------
/bin/docker-entrypoint:
--------------------------------------------------------------------------------
1 | #!/bin/bash -e
2 |
3 | # If running the rails server then create or migrate existing database
4 | if [ "${1}" == "./bin/rails" ] && [ "${2}" == "server" ]; then
5 | ./bin/rails db:prepare
6 | fi
7 |
8 | exec "${@}"
9 |
--------------------------------------------------------------------------------
/bin/importmap:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 |
3 | require_relative "../config/application"
4 | require "importmap/commands"
5 |
--------------------------------------------------------------------------------
/bin/rails:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | APP_PATH = File.expand_path("../config/application", __dir__)
3 | require_relative "../config/boot"
4 | require "rails/commands"
5 |
--------------------------------------------------------------------------------
/bin/rake:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | require_relative "../config/boot"
3 | require "rake"
4 | Rake.application.run
5 |
--------------------------------------------------------------------------------
/bin/setup:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | require "fileutils"
3 |
4 | # path to your application root.
5 | APP_ROOT = File.expand_path("..", __dir__)
6 |
7 | def system!(*args)
8 | system(*args, exception: true)
9 | end
10 |
11 | FileUtils.chdir APP_ROOT do
12 | # This script is a way to set up or update your development environment automatically.
13 | # This script is idempotent, so that you can run it at any time and get an expectable outcome.
14 | # Add necessary setup steps to this file.
15 |
16 | puts "== Installing dependencies =="
17 | system! "gem install bundler --conservative"
18 | system("bundle check") || system!("bundle install")
19 |
20 | # puts "\n== Copying sample files =="
21 | # unless File.exist?("config/database.yml")
22 | # FileUtils.cp "config/database.yml.sample", "config/database.yml"
23 | # end
24 |
25 | puts "\n== Preparing database =="
26 | system! "bin/rails db:prepare"
27 |
28 | puts "\n== Removing old logs and tempfiles =="
29 | system! "bin/rails log:clear tmp:clear"
30 |
31 | puts "\n== Restarting application server =="
32 | system! "bin/rails restart"
33 | end
34 |
--------------------------------------------------------------------------------
/config.ru:
--------------------------------------------------------------------------------
1 | # This file is used by Rack-based servers to start the application.
2 |
3 | require_relative "config/environment"
4 |
5 | run Rails.application
6 | Rails.application.load_server
7 |
--------------------------------------------------------------------------------
/config/application.rb:
--------------------------------------------------------------------------------
1 | require_relative "boot"
2 |
3 | require "rails"
4 | # Pick the frameworks you want:
5 | require "active_model/railtie"
6 | # require "active_job/railtie"
7 | require "active_record/railtie"
8 | # require "active_storage/engine"
9 | require "action_controller/railtie"
10 | # require "action_mailer/railtie"
11 | # require "action_mailbox/engine"
12 | # require "action_text/engine"
13 | require "action_view/railtie"
14 | # require "action_cable/engine"
15 | require "rails/test_unit/railtie"
16 |
17 | # Require the gems listed in Gemfile, including any gems
18 | # you've limited to :test, :development, or :production.
19 | Bundler.require(*Rails.groups)
20 |
21 | module RailsFrontendTest
22 | class Application < Rails::Application
23 | # Initialize configuration defaults for originally generated Rails version.
24 | config.load_defaults 7.1
25 |
26 | # Please, add to the `ignore` list any other `lib` subdirectories that do
27 | # not contain `.rb` files, or that should not be reloaded or eager loaded.
28 | # Common ones are `templates`, `generators`, or `middleware`, for example.
29 | config.autoload_lib(ignore: %w(assets tasks))
30 |
31 | # Configuration for the application, engines, and railties goes here.
32 | #
33 | # These settings can be overridden in specific environments using the files
34 | # in config/environments, which are processed later.
35 | #
36 | # config.time_zone = "Central Time (US & Canada)"
37 | # config.eager_load_paths << Rails.root.join("extras")
38 | end
39 | end
40 |
--------------------------------------------------------------------------------
/config/boot.rb:
--------------------------------------------------------------------------------
1 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
2 |
3 | require "bundler/setup" # Set up gems listed in the Gemfile.
4 | require "bootsnap/setup" # Speed up boot time by caching expensive operations.
5 |
--------------------------------------------------------------------------------
/config/credentials.yml.enc:
--------------------------------------------------------------------------------
1 | K9qPgOPTP7xBEup7BEDgdgymEtU0QhsazhhQ5ufCSP3m6Z5pqa16Gw1PiiGX1k4ccsiY41u4oJ249Y/2JJ9IgjQc5cTpwtC/KSbS1QDmE7W8PVdq7MeOZMRyyXsgJkPTgyfmVbfKU9c3JYk2BphfqtoREx3yeJv0ZPXaKCarMBltvWVfI+ofKCiJthmUyyrVpAuplNMGY27PfHBEYeMhgio5V7gYLRSamMFbC9vXiW72iIHAcC2T5LWfvSyElu15BKFwx9d2LohOxmKfesP+lXqYtVA8iWcJO4CuSIrsLEBcod3gSDwjPeC2r4eLNIW4a4WHzwDdwyRTmX1pkSi9w+FVZq1dN2zO2tWgCbTa4StqY3YcgTqWT8VcVlZtuZ+79z0oLP18TzVcDe3p4eMkU3YJn5HJ--OB6C2I8chSe/arFE--nvX4G9e5dcEGR/uWzwc5MQ==
--------------------------------------------------------------------------------
/config/database.yml:
--------------------------------------------------------------------------------
1 | # SQLite. Versions 3.8.0 and up are supported.
2 | # gem install sqlite3
3 | #
4 | # Ensure the SQLite 3 gem is defined in your Gemfile
5 | # gem "sqlite3"
6 | #
7 | default: &default
8 | adapter: sqlite3
9 | pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
10 | timeout: 5000
11 |
12 | development:
13 | <<: *default
14 | database: storage/development.sqlite3
15 |
16 | # Warning: The database defined as "test" will be erased and
17 | # re-generated from your development database when you run "rake".
18 | # Do not set this db to the same as development or production.
19 | test:
20 | <<: *default
21 | database: storage/test.sqlite3
22 |
23 | production:
24 | <<: *default
25 | database: storage/production.sqlite3
26 |
--------------------------------------------------------------------------------
/config/environment.rb:
--------------------------------------------------------------------------------
1 | # Load the Rails application.
2 | require_relative "application"
3 |
4 | # Initialize the Rails application.
5 | Rails.application.initialize!
6 |
--------------------------------------------------------------------------------
/config/environments/development.rb:
--------------------------------------------------------------------------------
1 | require "active_support/core_ext/integer/time"
2 |
3 | Rails.application.configure do
4 | # Settings specified here will take precedence over those in config/application.rb.
5 |
6 | # In the development environment your application's code is reloaded any time
7 | # it changes. This slows down response time but is perfect for development
8 | # since you don't have to restart the web server when you make code changes.
9 | config.enable_reloading = true
10 |
11 | # Do not eager load code on boot.
12 | config.eager_load = false
13 |
14 | # Show full error reports.
15 | config.consider_all_requests_local = true
16 |
17 | # Enable server timing
18 | config.server_timing = true
19 |
20 | # Enable/disable caching. By default caching is disabled.
21 | # Run rails dev:cache to toggle caching.
22 | if Rails.root.join("tmp/caching-dev.txt").exist?
23 | config.action_controller.perform_caching = true
24 | config.action_controller.enable_fragment_cache_logging = true
25 |
26 | config.cache_store = :memory_store
27 | config.public_file_server.headers = {
28 | "Cache-Control" => "public, max-age=#{2.days.to_i}"
29 | }
30 | else
31 | config.action_controller.perform_caching = false
32 |
33 | config.cache_store = :null_store
34 | end
35 |
36 | # Print deprecation notices to the Rails logger.
37 | config.active_support.deprecation = :log
38 |
39 | # Raise exceptions for disallowed deprecations.
40 | config.active_support.disallowed_deprecation = :raise
41 |
42 | # Tell Active Support which deprecation messages to disallow.
43 | config.active_support.disallowed_deprecation_warnings = []
44 |
45 | # Raise an error on page load if there are pending migrations.
46 | config.active_record.migration_error = :page_load
47 |
48 | # Highlight code that triggered database queries in logs.
49 | config.active_record.verbose_query_logs = true
50 |
51 | # Suppress logger output for asset requests.
52 | config.assets.quiet = true
53 |
54 | # Raises error for missing translations.
55 | # config.i18n.raise_on_missing_translations = true
56 |
57 | # Annotate rendered view with file names.
58 | # config.action_view.annotate_rendered_view_with_filenames = true
59 |
60 | # Raise error when a before_action's only/except options reference missing actions
61 | config.action_controller.raise_on_missing_callback_actions = true
62 | end
63 |
--------------------------------------------------------------------------------
/config/environments/production.rb:
--------------------------------------------------------------------------------
1 | require "active_support/core_ext/integer/time"
2 |
3 | Rails.application.configure do
4 | # Settings specified here will take precedence over those in config/application.rb.
5 |
6 | # Code is not reloaded between requests.
7 | config.enable_reloading = false
8 |
9 | # Eager load code on boot. This eager loads most of Rails and
10 | # your application in memory, allowing both threaded web servers
11 | # and those relying on copy on write to perform better.
12 | # Rake tasks automatically ignore this option for performance.
13 | config.eager_load = true
14 |
15 | # Full error reports are disabled and caching is turned on.
16 | config.consider_all_requests_local = false
17 | config.action_controller.perform_caching = true
18 |
19 | # Ensures that a master key has been made available in ENV["RAILS_MASTER_KEY"], config/master.key, or an environment
20 | # key such as config/credentials/production.key. This key is used to decrypt credentials (and other encrypted files).
21 | # config.require_master_key = true
22 |
23 | # Disable serving static files from `public/`, relying on NGINX/Apache to do so instead.
24 | # config.public_file_server.enabled = false
25 |
26 | # Compress CSS using a preprocessor.
27 | # config.assets.css_compressor = :sass
28 |
29 | # Do not fallback to assets pipeline if a precompiled asset is missed.
30 | config.assets.compile = false
31 |
32 | # Enable serving of images, stylesheets, and JavaScripts from an asset server.
33 | # config.asset_host = "http://assets.example.com"
34 |
35 | # Specifies the header that your server uses for sending files.
36 | # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for Apache
37 | # config.action_dispatch.x_sendfile_header = "X-Accel-Redirect" # for NGINX
38 |
39 | # Assume all access to the app is happening through a SSL-terminating reverse proxy.
40 | # Can be used together with config.force_ssl for Strict-Transport-Security and secure cookies.
41 | # config.assume_ssl = true
42 |
43 | # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
44 | config.force_ssl = true
45 |
46 | # Log to STDOUT by default
47 | config.logger = ActiveSupport::Logger.new(STDOUT)
48 | .tap { |logger| logger.formatter = ::Logger::Formatter.new }
49 | .then { |logger| ActiveSupport::TaggedLogging.new(logger) }
50 |
51 | # Prepend all log lines with the following tags.
52 | config.log_tags = [ :request_id ]
53 |
54 | # Info include generic and useful information about system operation, but avoids logging too much
55 | # information to avoid inadvertent exposure of personally identifiable information (PII). If you
56 | # want to log everything, set the level to "debug".
57 | config.log_level = ENV.fetch("RAILS_LOG_LEVEL", "info")
58 |
59 | # Use a different cache store in production.
60 | # config.cache_store = :mem_cache_store
61 |
62 | # Enable locale fallbacks for I18n (makes lookups for any locale fall back to
63 | # the I18n.default_locale when a translation cannot be found).
64 | config.i18n.fallbacks = true
65 |
66 | # Don't log any deprecations.
67 | config.active_support.report_deprecations = false
68 |
69 | # Do not dump schema after migrations.
70 | config.active_record.dump_schema_after_migration = false
71 |
72 | # Enable DNS rebinding protection and other `Host` header attacks.
73 | # config.hosts = [
74 | # "example.com", # Allow requests from example.com
75 | # /.*\.example\.com/ # Allow requests from subdomains like `www.example.com`
76 | # ]
77 | # Skip DNS rebinding protection for the default health check endpoint.
78 | # config.host_authorization = { exclude: ->(request) { request.path == "/up" } }
79 | end
80 |
--------------------------------------------------------------------------------
/config/environments/test.rb:
--------------------------------------------------------------------------------
1 | require "active_support/core_ext/integer/time"
2 |
3 | # The test environment is used exclusively to run your application's
4 | # test suite. You never need to work with it otherwise. Remember that
5 | # your test database is "scratch space" for the test suite and is wiped
6 | # and recreated between test runs. Don't rely on the data there!
7 |
8 | Rails.application.configure do
9 | # Settings specified here will take precedence over those in config/application.rb.
10 |
11 | # While tests run files are not watched, reloading is not necessary.
12 | config.enable_reloading = false
13 |
14 | # Eager loading loads your entire application. When running a single test locally,
15 | # this is usually not necessary, and can slow down your test suite. However, it's
16 | # recommended that you enable it in continuous integration systems to ensure eager
17 | # loading is working properly before deploying your code.
18 | config.eager_load = ENV["CI"].present?
19 |
20 | # Configure public file server for tests with Cache-Control for performance.
21 | config.public_file_server.enabled = true
22 | config.public_file_server.headers = {
23 | "Cache-Control" => "public, max-age=#{1.hour.to_i}"
24 | }
25 |
26 | # Show full error reports and disable caching.
27 | config.consider_all_requests_local = true
28 | config.action_controller.perform_caching = false
29 | config.cache_store = :null_store
30 |
31 | # Render exception templates for rescuable exceptions and raise for other exceptions.
32 | config.action_dispatch.show_exceptions = :rescuable
33 |
34 | # Disable request forgery protection in test environment.
35 | config.action_controller.allow_forgery_protection = false
36 |
37 | # Print deprecation notices to the stderr.
38 | config.active_support.deprecation = :stderr
39 |
40 | # Raise exceptions for disallowed deprecations.
41 | config.active_support.disallowed_deprecation = :raise
42 |
43 | # Tell Active Support which deprecation messages to disallow.
44 | config.active_support.disallowed_deprecation_warnings = []
45 |
46 | # Raises error for missing translations.
47 | # config.i18n.raise_on_missing_translations = true
48 |
49 | # Annotate rendered view with file names.
50 | # config.action_view.annotate_rendered_view_with_filenames = true
51 |
52 | # Raise error when a before_action's only/except options reference missing actions
53 | config.action_controller.raise_on_missing_callback_actions = true
54 | end
55 |
--------------------------------------------------------------------------------
/config/importmap.rb:
--------------------------------------------------------------------------------
1 | # Pin npm packages by running ./bin/importmap
2 |
3 | pin "application", preload: true
4 | pin "@hotwired/turbo-rails", to: "turbo.min.js", preload: true
5 | pin "@hotwired/stimulus", to: "stimulus.min.js", preload: true
6 | pin "@hotwired/stimulus-loading", to: "stimulus-loading.js", preload: true
7 | pin_all_from "app/javascript/controllers", under: "controllers"
8 | pin "jquery", to: "https://ga.jspm.io/npm:jquery@3.7.1/dist/jquery.js"
9 | pin "sortablejs", to: "https://ga.jspm.io/npm:sortablejs@1.15.1/modular/sortable.esm.js"
10 |
--------------------------------------------------------------------------------
/config/initializers/assets.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # Version of your assets, change this if you want to expire all your assets.
4 | Rails.application.config.assets.version = "1.0"
5 |
6 | # Add additional assets to the asset load path.
7 | # Rails.application.config.assets.paths << Emoji.images_path
8 |
9 | # Precompile additional assets.
10 | # application.js, application.css, and all non-JS/CSS in the app/assets
11 | # folder are already added.
12 | # Rails.application.config.assets.precompile += %w( admin.js admin.css )
13 |
--------------------------------------------------------------------------------
/config/initializers/content_security_policy.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # Define an application-wide content security policy.
4 | # See the Securing Rails Applications Guide for more information:
5 | # https://guides.rubyonrails.org/security.html#content-security-policy-header
6 |
7 | # Rails.application.configure do
8 | # config.content_security_policy do |policy|
9 | # policy.default_src :self, :https
10 | # policy.font_src :self, :https, :data
11 | # policy.img_src :self, :https, :data
12 | # policy.object_src :none
13 | # policy.script_src :self, :https
14 | # policy.style_src :self, :https
15 | # # Specify URI for violation reports
16 | # # policy.report_uri "/csp-violation-report-endpoint"
17 | # end
18 | #
19 | # # Generate session nonces for permitted importmap, inline scripts, and inline styles.
20 | # config.content_security_policy_nonce_generator = ->(request) { request.session.id.to_s }
21 | # config.content_security_policy_nonce_directives = %w(script-src style-src)
22 | #
23 | # # Report violations without enforcing the policy.
24 | # # config.content_security_policy_report_only = true
25 | # end
26 |
--------------------------------------------------------------------------------
/config/initializers/filter_parameter_logging.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # Configure parameters to be partially matched (e.g. passw matches password) and filtered from the log file.
4 | # Use this to limit dissemination of sensitive information.
5 | # See the ActiveSupport::ParameterFilter documentation for supported notations and behaviors.
6 | Rails.application.config.filter_parameters += [
7 | :passw, :secret, :token, :_key, :crypt, :salt, :certificate, :otp, :ssn
8 | ]
9 |
--------------------------------------------------------------------------------
/config/initializers/inflections.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # Add new inflection rules using the following format. Inflections
4 | # are locale specific, and you may define rules for as many different
5 | # locales as you wish. All of these examples are active by default:
6 | # ActiveSupport::Inflector.inflections(:en) do |inflect|
7 | # inflect.plural /^(ox)$/i, "\\1en"
8 | # inflect.singular /^(ox)en/i, "\\1"
9 | # inflect.irregular "person", "people"
10 | # inflect.uncountable %w( fish sheep )
11 | # end
12 |
13 | # These inflection rules are supported but not enabled by default:
14 | # ActiveSupport::Inflector.inflections(:en) do |inflect|
15 | # inflect.acronym "RESTful"
16 | # end
17 |
--------------------------------------------------------------------------------
/config/initializers/permissions_policy.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # Define an application-wide HTTP permissions policy. For further
4 | # information see: https://developers.google.com/web/updates/2018/06/feature-policy
5 |
6 | # Rails.application.config.permissions_policy do |policy|
7 | # policy.camera :none
8 | # policy.gyroscope :none
9 | # policy.microphone :none
10 | # policy.usb :none
11 | # policy.fullscreen :self
12 | # policy.payment :self, "https://secure.example.com"
13 | # end
14 |
--------------------------------------------------------------------------------
/config/initializers/simple_form.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | #
3 | # Uncomment this and change the path if necessary to include your own
4 | # components.
5 | # See https://github.com/heartcombo/simple_form#custom-components to know
6 | # more about custom components.
7 | # Dir[Rails.root.join('lib/components/**/*.rb')].each { |f| require f }
8 | #
9 | # Use this setup block to configure all options available in SimpleForm.
10 | SimpleForm.setup do |config|
11 | # Wrappers are used by the form builder to generate a
12 | # complete input. You can remove any component from the
13 | # wrapper, change the order or even add your own to the
14 | # stack. The options given below are used to wrap the
15 | # whole input.
16 | config.wrappers :default, class: :input,
17 | hint_class: :field_with_hint, error_class: :field_with_errors, valid_class: :field_without_errors do |b|
18 | ## Extensions enabled by default
19 | # Any of these extensions can be disabled for a
20 | # given input by passing: `f.input EXTENSION_NAME => false`.
21 | # You can make any of these extensions optional by
22 | # renaming `b.use` to `b.optional`.
23 |
24 | # Determines whether to use HTML5 (:email, :url, ...)
25 | # and required attributes
26 | b.use :html5
27 |
28 | # Calculates placeholders automatically from I18n
29 | # You can also pass a string as f.input placeholder: "Placeholder"
30 | b.use :placeholder
31 |
32 | ## Optional extensions
33 | # They are disabled unless you pass `f.input EXTENSION_NAME => true`
34 | # to the input. If so, they will retrieve the values from the model
35 | # if any exists. If you want to enable any of those
36 | # extensions by default, you can change `b.optional` to `b.use`.
37 |
38 | # Calculates maxlength from length validations for string inputs
39 | # and/or database column lengths
40 | b.optional :maxlength
41 |
42 | # Calculate minlength from length validations for string inputs
43 | b.optional :minlength
44 |
45 | # Calculates pattern from format validations for string inputs
46 | b.optional :pattern
47 |
48 | # Calculates min and max from length validations for numeric inputs
49 | b.optional :min_max
50 |
51 | # Calculates readonly automatically from readonly attributes
52 | b.optional :readonly
53 |
54 | ## Inputs
55 | # b.use :input, class: 'input', error_class: 'is-invalid', valid_class: 'is-valid'
56 | b.use :label_input
57 | b.use :hint, wrap_with: { tag: :span, class: :hint }
58 | b.use :error, wrap_with: { tag: :span, class: :error }
59 |
60 | ## full_messages_for
61 | # If you want to display the full error message for the attribute, you can
62 | # use the component :full_error, like:
63 | #
64 | # b.use :full_error, wrap_with: { tag: :span, class: :error }
65 | end
66 |
67 | # The default wrapper to be used by the FormBuilder.
68 | config.default_wrapper = :default
69 |
70 | # Define the way to render check boxes / radio buttons with labels.
71 | # Defaults to :nested for bootstrap config.
72 | # inline: input + label
73 | # nested: label > input
74 | config.boolean_style = :nested
75 |
76 | # Default class for buttons
77 | config.button_class = 'btn'
78 |
79 | # Method used to tidy up errors. Specify any Rails Array method.
80 | # :first lists the first message for each field.
81 | # Use :to_sentence to list all errors for each field.
82 | # config.error_method = :first
83 |
84 | # Default tag used for error notification helper.
85 | config.error_notification_tag = :div
86 |
87 | # CSS class to add for error notification helper.
88 | config.error_notification_class = 'error_notification'
89 |
90 | # Series of attempts to detect a default label method for collection.
91 | # config.collection_label_methods = [ :to_label, :name, :title, :to_s ]
92 |
93 | # Series of attempts to detect a default value method for collection.
94 | # config.collection_value_methods = [ :id, :to_s ]
95 |
96 | # You can wrap a collection of radio/check boxes in a pre-defined tag, defaulting to none.
97 | # config.collection_wrapper_tag = nil
98 |
99 | # You can define the class to use on all collection wrappers. Defaulting to none.
100 | # config.collection_wrapper_class = nil
101 |
102 | # You can wrap each item in a collection of radio/check boxes with a tag,
103 | # defaulting to :span.
104 | # config.item_wrapper_tag = :span
105 |
106 | # You can define a class to use in all item wrappers. Defaulting to none.
107 | # config.item_wrapper_class = nil
108 |
109 | # How the label text should be generated altogether with the required text.
110 | # config.label_text = lambda { |label, required, explicit_label| "#{required} #{label}" }
111 |
112 | # You can define the class to use on all labels. Default is nil.
113 | # config.label_class = nil
114 |
115 | # You can define the default class to be used on forms. Can be overridden
116 | # with `html: { :class }`. Defaulting to none.
117 | # config.default_form_class = nil
118 |
119 | # You can define which elements should obtain additional classes
120 | # config.generate_additional_classes_for = [:wrapper, :label, :input]
121 |
122 | # Whether attributes are required by default (or not). Default is true.
123 | # config.required_by_default = true
124 |
125 | # Tell browsers whether to use the native HTML5 validations (novalidate form option).
126 | # These validations are enabled in SimpleForm's internal config but disabled by default
127 | # in this configuration, which is recommended due to some quirks from different browsers.
128 | # To stop SimpleForm from generating the novalidate option, enabling the HTML5 validations,
129 | # change this configuration to true.
130 | config.browser_validations = false
131 |
132 | # Custom mappings for input types. This should be a hash containing a regexp
133 | # to match as key, and the input type that will be used when the field name
134 | # matches the regexp as value.
135 | # config.input_mappings = { /count/ => :integer }
136 |
137 | # Custom wrappers for input types. This should be a hash containing an input
138 | # type as key and the wrapper that will be used for all inputs with specified type.
139 | # config.wrapper_mappings = { string: :prepend }
140 |
141 | # Namespaces where SimpleForm should look for custom input classes that
142 | # override default inputs.
143 | # config.custom_inputs_namespaces << "CustomInputs"
144 |
145 | # Default priority for time_zone inputs.
146 | # config.time_zone_priority = nil
147 |
148 | # Default priority for country inputs.
149 | # config.country_priority = nil
150 |
151 | # When false, do not use translations for labels.
152 | # config.translate_labels = true
153 |
154 | # Automatically discover new inputs in Rails' autoload path.
155 | # config.inputs_discovery = true
156 |
157 | # Cache SimpleForm inputs discovery
158 | # config.cache_discovery = !Rails.env.development?
159 |
160 | # Default class for inputs
161 | # config.input_class = nil
162 |
163 | # Define the default class of the input wrapper of the boolean input.
164 | config.boolean_label_class = 'checkbox'
165 |
166 | # Defines if the default input wrapper class should be included in radio
167 | # collection wrappers.
168 | # config.include_default_input_wrapper_class = true
169 |
170 | # Defines which i18n scope will be used in Simple Form.
171 | # config.i18n_scope = 'simple_form'
172 |
173 | # Defines validation classes to the input_field. By default it's nil.
174 | # config.input_field_valid_class = 'is-valid'
175 | # config.input_field_error_class = 'is-invalid'
176 | end
177 |
--------------------------------------------------------------------------------
/config/initializers/simple_form_tailwind.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | # Use this setup block to configure all options available in SimpleForm.
4 | SimpleForm.setup do |config|
5 | # Default class for buttons
6 | config.button_class = 'my-2 bg-blue-500 hover:bg-blue-700 text-white font-bold text-sm py-2 px-4 rounded'
7 |
8 | # Define the default class of the input wrapper of the boolean input.
9 | config.boolean_label_class = ''
10 |
11 | # How the label text should be generated altogether with the required text.
12 | config.label_text = lambda { |label, required, explicit_label| "#{label} #{required}" }
13 |
14 | # Define the way to render check boxes / radio buttons with labels.
15 | config.boolean_style = :inline
16 |
17 | # You can wrap each item in a collection of radio/check boxes with a tag
18 | config.item_wrapper_tag = :div
19 |
20 | # Defines if the default input wrapper class should be included in radio
21 | # collection wrappers.
22 | config.include_default_input_wrapper_class = false
23 |
24 | # CSS class to add for error notification helper.
25 | config.error_notification_class = 'text-white px-6 py-4 border-0 rounded relative mb-4 bg-red-400'
26 |
27 | # Method used to tidy up errors. Specify any Rails Array method.
28 | # :first lists the first message for each field.
29 | # :to_sentence to list all errors for each field.
30 | config.error_method = :to_sentence
31 |
32 | # add validation classes to `input_field`
33 | config.input_field_error_class = 'border-red-500'
34 | config.input_field_valid_class = 'border-green-400'
35 | config.label_class = 'text-sm font-medium text-gray-600'
36 |
37 |
38 | # vertical forms
39 | #
40 | # vertical default_wrapper
41 | config.wrappers :vertical_form, tag: 'div', class: 'mb-4' do |b|
42 | b.use :html5
43 | b.use :placeholder
44 | b.optional :maxlength
45 | b.optional :minlength
46 | b.optional :pattern
47 | b.optional :min_max
48 | b.optional :readonly
49 | b.use :label, class: 'block', error_class: 'text-red-500'
50 | b.use :input, class: 'shadow appearance-none border border-gray-300 rounded w-full py-2 px-3 bg-white focus:outline-none focus:ring-0 focus:border-blue-500 text-gray-400 leading-6 transition-colors duration-200 ease-in-out', error_class: 'border-red-500', valid_class: 'border-green-400'
51 | b.use :full_error, wrap_with: { tag: 'p', class: 'mt-2 text-red-500 text-xs italic' }
52 | b.use :hint, wrap_with: { tag: 'p', class: 'mt-2 text-grey-700 text-xs italic' }
53 | end
54 |
55 | # vertical input for boolean (aka checkboxes)
56 | config.wrappers :vertical_boolean, tag: 'div', class: 'mb-4 flex items-start', error_class: '' do |b|
57 | b.use :html5
58 | b.optional :readonly
59 | b.wrapper tag: 'div', class: 'flex items-center h-5' do |ba|
60 | ba.use :input, class: 'focus:ring-2 focus:ring-indigo-500 ring-offset-2 h-4 w-4 text-indigo-600 border-gray-300 rounded'
61 | end
62 | b.wrapper tag: 'div', class: 'ml-3 text-sm' do |bb|
63 | bb.use :label, class: 'block', error_class: 'text-red-500'
64 | bb.use :hint, wrap_with: { tag: 'p', class: 'block text-grey-700 text-xs italic' }
65 | bb.use :full_error, wrap_with: { tag: 'p', class: 'block text-red-500 text-xs italic' }
66 | end
67 |
68 | end
69 |
70 | # vertical input for radio buttons and check boxes
71 | config.wrappers :vertical_collection, item_wrapper_class: 'flex items-center', item_label_class: 'my-1 ml-3 block text-sm font-medium text-gray-400', tag: 'div', class: 'my-4' do |b|
72 | b.use :html5
73 | b.optional :readonly
74 | b.wrapper :legend_tag, tag: 'legend', class: 'text-sm font-medium text-gray-600', error_class: 'text-red-500' do |ba|
75 | ba.use :label_text
76 | end
77 | b.use :input, class: 'focus:ring-2 focus:ring-indigo-500 ring-offset-2 h-4 w-4 text-indigo-600 border-gray-300 rounded', error_class: 'text-red-500', valid_class: 'text-green-400'
78 | b.use :full_error, wrap_with: { tag: 'p', class: 'block mt-2 text-red-500 text-xs italic' }
79 | b.use :hint, wrap_with: { tag: 'p', class: 'mt-2 text-grey-700 text-xs italic' }
80 | end
81 |
82 | # vertical file input
83 | config.wrappers :vertical_file, tag: 'div', class: '' do |b|
84 | b.use :html5
85 | b.use :placeholder
86 | b.optional :maxlength
87 | b.optional :minlength
88 | b.optional :readonly
89 | b.use :label, class: 'text-sm font-medium text-gray-600 block', error_class: 'text-red-500'
90 | b.use :input, class: 'w-full text-gray-500 px-3 py-2 border rounded', error_class: 'text-red-500 border-red-500', valid_class: 'text-green-400'
91 | b.use :full_error, wrap_with: { tag: 'p', class: 'mt-2 text-red-500 text-xs italic' }
92 | b.use :hint, wrap_with: { tag: 'p', class: 'mt-2 text-grey-700 text-xs italic' }
93 | end
94 |
95 | # vertical multi select
96 | config.wrappers :vertical_multi_select, tag: 'div', class: 'my-4', error_class: 'f', valid_class: '' do |b|
97 | b.use :html5
98 | b.optional :readonly
99 | b.wrapper :legend_tag, tag: 'legend', class: 'text-sm font-medium text-gray-600', error_class: 'text-red-500' do |ba|
100 | ba.use :label_text
101 | end
102 | b.wrapper tag: 'div', class: 'inline-flex space-x-1' do |ba|
103 | # ba.use :input, class: 'flex w-auto w-auto text-gray-500 text-sm border-gray-300 rounded p-2', error_class: 'text-red-500', valid_class: 'text-green-400'
104 | ba.use :input, class: 'flex w-auto w-auto shadow appearance-none border border-gray-300 rounded w-full p-2 bg-white focus:outline-none focus:border-blue-500 text-gray-400 leading-4 transition-colors duration-200 ease-in-out'
105 | end
106 | b.use :full_error, wrap_with: { tag: 'p', class: 'mt-2 text-red-500 text-xs italic' }
107 | b.use :hint, wrap_with: { tag: 'p', class: 'mt-2 text-grey-700 text-xs italic' }
108 | end
109 |
110 | # vertical range input
111 | config.wrappers :vertical_range, tag: 'div', class: 'my-4', error_class: 'text-red-500', valid_class: 'text-green-400' do |b|
112 | b.use :html5
113 | b.use :placeholder
114 | b.optional :readonly
115 | b.optional :step
116 | b.use :label, class: 'text-sm font-medium text-gray-600 block', error_class: 'text-red-500'
117 | b.wrapper tag: 'div', class: 'flex items-center h-5' do |ba|
118 | ba.use :input, class: 'rounded-lg overflow-hidden appearance-none bg-gray-400 h-3 w-full text-gray-300', error_class: 'text-red-500', valid_class: 'text-green-400'
119 | end
120 | b.use :full_error, wrap_with: { tag: 'p', class: 'mt-2 text-red-500 text-xs italic' }
121 | b.use :hint, wrap_with: { tag: 'p', class: 'mt-2 text-grey-700 text-xs italic' }
122 | end
123 |
124 | # The default wrapper to be used by the FormBuilder.
125 | config.default_wrapper = :vertical_form
126 |
127 | # Custom wrappers for input types. This should be a hash containing an input
128 | # type as key and the wrapper that will be used for all inputs with specified type.
129 | config.wrapper_mappings = {
130 | boolean: :vertical_boolean,
131 | check_boxes: :vertical_collection,
132 | date: :vertical_multi_select,
133 | datetime: :vertical_multi_select,
134 | file: :vertical_file,
135 | radio_buttons: :vertical_collection,
136 | range: :vertical_range,
137 | time: :vertical_multi_select
138 | }
139 | end
140 |
--------------------------------------------------------------------------------
/config/locales/en.yml:
--------------------------------------------------------------------------------
1 | # Files in the config/locales directory are used for internationalization and
2 | # are automatically loaded by Rails. If you want to use locales other than
3 | # English, add the necessary files in this directory.
4 | #
5 | # To use the locales, use `I18n.t`:
6 | #
7 | # I18n.t "hello"
8 | #
9 | # In views, this is aliased to just `t`:
10 | #
11 | # <%= t("hello") %>
12 | #
13 | # To use a different locale, set it with `I18n.locale`:
14 | #
15 | # I18n.locale = :es
16 | #
17 | # This would use the information in config/locales/es.yml.
18 | #
19 | # To learn more about the API, please read the Rails Internationalization guide
20 | # at https://guides.rubyonrails.org/i18n.html.
21 | #
22 | # Be aware that YAML interprets the following case-insensitive strings as
23 | # booleans: `true`, `false`, `on`, `off`, `yes`, `no`. Therefore, these strings
24 | # must be quoted to be interpreted as strings. For example:
25 | #
26 | # en:
27 | # "yes": yup
28 | # enabled: "ON"
29 |
30 | en:
31 | hello: "Hello world"
32 |
--------------------------------------------------------------------------------
/config/locales/simple_form.en.yml:
--------------------------------------------------------------------------------
1 | en:
2 | simple_form:
3 | "yes": 'Yes'
4 | "no": 'No'
5 | required:
6 | text: 'required'
7 | mark: '*'
8 | # You can uncomment the line below if you need to overwrite the whole required html.
9 | # When using html, text and mark won't be used.
10 | # html: '*'
11 | error_notification:
12 | default_message: "Please review the problems below:"
13 | # Examples
14 | # labels:
15 | # defaults:
16 | # password: 'Password'
17 | # user:
18 | # new:
19 | # email: 'E-mail to sign in.'
20 | # edit:
21 | # email: 'E-mail.'
22 | # hints:
23 | # defaults:
24 | # username: 'User name to sign in.'
25 | # password: 'No special characters, please.'
26 | # include_blanks:
27 | # defaults:
28 | # age: 'Rather not say'
29 | # prompts:
30 | # defaults:
31 | # age: 'Select your age'
32 |
--------------------------------------------------------------------------------
/config/puma.rb:
--------------------------------------------------------------------------------
1 | # This configuration file will be evaluated by Puma. The top-level methods that
2 | # are invoked here are part of Puma's configuration DSL. For more information
3 | # about methods provided by the DSL, see https://puma.io/puma/Puma/DSL.html.
4 |
5 | # Puma can serve each request in a thread from an internal thread pool.
6 | # The `threads` method setting takes two numbers: a minimum and maximum.
7 | # Any libraries that use thread pools should be configured to match
8 | # the maximum value specified for Puma. Default is set to 5 threads for minimum
9 | # and maximum; this matches the default thread size of Active Record.
10 | max_threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 }
11 | min_threads_count = ENV.fetch("RAILS_MIN_THREADS") { max_threads_count }
12 | threads min_threads_count, max_threads_count
13 |
14 | # Specifies that the worker count should equal the number of processors in production.
15 | if ENV["RAILS_ENV"] == "production"
16 | require "concurrent-ruby"
17 | worker_count = Integer(ENV.fetch("WEB_CONCURRENCY") { Concurrent.physical_processor_count })
18 | workers worker_count if worker_count > 1
19 | end
20 |
21 | # Specifies the `worker_timeout` threshold that Puma will use to wait before
22 | # terminating a worker in development environments.
23 | worker_timeout 3600 if ENV.fetch("RAILS_ENV", "development") == "development"
24 |
25 | # Specifies the `port` that Puma will listen on to receive requests; default is 3000.
26 | port ENV.fetch("PORT") { 3000 }
27 |
28 | # Specifies the `environment` that Puma will run in.
29 | environment ENV.fetch("RAILS_ENV") { "development" }
30 |
31 | # Specifies the `pidfile` that Puma will use.
32 | pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" }
33 |
34 | # Allow puma to be restarted by `bin/rails restart` command.
35 | plugin :tmp_restart
36 |
--------------------------------------------------------------------------------
/config/routes.rb:
--------------------------------------------------------------------------------
1 | Rails.application.routes.draw do
2 | resources :storefronts
3 | resources :reasons do
4 | patch 'update_order', on: :member
5 | end
6 | # Define your application routes per the DSL in https://guides.rubyonrails.org/routing.html
7 |
8 | # Reveal health status on /up that returns 200 if the app boots with no exceptions, otherwise 500.
9 | # Can be used by load balancers and uptime monitors to verify that the app is live.
10 | get "up" => "rails/health#show", as: :rails_health_check
11 |
12 | # Defines the root path route ("/")
13 | root "storefronts#edit", id: 1
14 | end
15 |
--------------------------------------------------------------------------------
/config/tailwind.config.js:
--------------------------------------------------------------------------------
1 | const defaultTheme = require('tailwindcss/defaultTheme')
2 |
3 | module.exports = {
4 | content: [
5 | './public/*.html',
6 | './app/helpers/**/*.rb',
7 | './app/javascript/**/*.js',
8 | './app/views/**/*.{erb,haml,html,slim}'
9 | ],
10 | theme: {
11 | extend: {
12 | fontFamily: {
13 | sans: ['Inter var', ...defaultTheme.fontFamily.sans],
14 | },
15 | },
16 | },
17 | plugins: [
18 | require('@tailwindcss/forms'),
19 | require('@tailwindcss/aspect-ratio'),
20 | require('@tailwindcss/typography'),
21 | require('@tailwindcss/container-queries'),
22 | ]
23 | }
24 |
--------------------------------------------------------------------------------
/db/migrate/20231221221744_create_storefronts.rb:
--------------------------------------------------------------------------------
1 | class CreateStorefronts < ActiveRecord::Migration[7.1]
2 | def change
3 | create_table :storefronts do |t|
4 | t.string :name
5 | t.timestamps
6 | end
7 |
8 | add_index :storefronts, :name, unique: true
9 | end
10 | end
11 |
--------------------------------------------------------------------------------
/db/migrate/20231221221802_create_reasons.rb:
--------------------------------------------------------------------------------
1 | class CreateReasons < ActiveRecord::Migration[7.1]
2 | def change
3 | create_table :reasons do |t|
4 | t.references :storefront, null: false, foreign_key: true
5 | t.string :code
6 | t.string :label
7 | t.json :restricted_resolution_types
8 | t.boolean :active
9 | t.integer :ordering
10 |
11 | t.timestamps
12 | end
13 |
14 | add_index :reasons, [:storefront_id, :code], unique: true
15 | end
16 | end
17 |
--------------------------------------------------------------------------------
/db/schema.rb:
--------------------------------------------------------------------------------
1 | # This file is auto-generated from the current state of the database. Instead
2 | # of editing this file, please use the migrations feature of Active Record to
3 | # incrementally modify your database, and then regenerate this schema definition.
4 | #
5 | # This file is the source Rails uses to define your schema when running `bin/rails
6 | # db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to
7 | # be faster and is potentially less error prone than running all of your
8 | # migrations from scratch. Old migrations may fail to apply correctly if those
9 | # migrations use external dependencies or application code.
10 | #
11 | # It's strongly recommended that you check this file into your version control system.
12 |
13 | ActiveRecord::Schema[7.1].define(version: 2023_12_21_221802) do
14 | create_table "reasons", force: :cascade do |t|
15 | t.integer "storefront_id", null: false
16 | t.string "code"
17 | t.string "label"
18 | t.json "restricted_resolution_types"
19 | t.boolean "active"
20 | t.integer "ordering"
21 | t.datetime "created_at", null: false
22 | t.datetime "updated_at", null: false
23 | t.index ["storefront_id", "code"], name: "index_reasons_on_storefront_id_and_code", unique: true
24 | t.index ["storefront_id"], name: "index_reasons_on_storefront_id"
25 | end
26 |
27 | create_table "storefronts", force: :cascade do |t|
28 | t.string "name"
29 | t.datetime "created_at", null: false
30 | t.datetime "updated_at", null: false
31 | t.index ["name"], name: "index_storefronts_on_name", unique: true
32 | end
33 |
34 | add_foreign_key "reasons", "storefronts"
35 | end
36 |
--------------------------------------------------------------------------------
/db/seeds.rb:
--------------------------------------------------------------------------------
1 | # This file should ensure the existence of records required to run the application in every environment (production,
2 | # development, test). The code here should be idempotent so that it can be executed at any point in every environment.
3 | # The data can then be loaded with the bin/rails db:seed command (or created alongside the database with db:setup).
4 | #
5 | # Example:
6 | #
7 | # ["Action", "Comedy", "Drama", "Horror"].each do |genre_name|
8 | # MovieGenre.find_or_create_by!(name: genre_name)
9 | # end
10 |
--------------------------------------------------------------------------------
/lib/assets/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/abbasikov/Rails-frontend-test/0497c2ac2853f300ba20419e89a96a08cc686c9a/lib/assets/.keep
--------------------------------------------------------------------------------
/lib/tasks/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/abbasikov/Rails-frontend-test/0497c2ac2853f300ba20419e89a96a08cc686c9a/lib/tasks/.keep
--------------------------------------------------------------------------------
/log/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/abbasikov/Rails-frontend-test/0497c2ac2853f300ba20419e89a96a08cc686c9a/log/.keep
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "dependencies": {
3 | "jquery": "^3.7.1",
4 | "sortablejs": "^1.15.1"
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/public/404.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | The page you were looking for doesn't exist (404)
5 |
6 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
The page you were looking for doesn't exist.
62 |
You may have mistyped the address or the page may have moved.
63 |
64 |
If you are the application owner check the logs for more information.
65 |
66 |
67 |
68 |
--------------------------------------------------------------------------------
/public/422.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | The change you wanted was rejected (422)
5 |
6 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
The change you wanted was rejected.
62 |
Maybe you tried to change something you didn't have access to.
63 |
64 |
If you are the application owner check the logs for more information.
65 |
66 |
67 |
68 |
--------------------------------------------------------------------------------
/public/500.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | We're sorry, but something went wrong (500)
5 |
6 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
We're sorry, but something went wrong.
62 |
63 |
If you are the application owner check the logs for more information.
64 |
65 |
66 |
67 |
--------------------------------------------------------------------------------
/public/apple-touch-icon-precomposed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/abbasikov/Rails-frontend-test/0497c2ac2853f300ba20419e89a96a08cc686c9a/public/apple-touch-icon-precomposed.png
--------------------------------------------------------------------------------
/public/apple-touch-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/abbasikov/Rails-frontend-test/0497c2ac2853f300ba20419e89a96a08cc686c9a/public/apple-touch-icon.png
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/abbasikov/Rails-frontend-test/0497c2ac2853f300ba20419e89a96a08cc686c9a/public/favicon.ico
--------------------------------------------------------------------------------
/public/robots.txt:
--------------------------------------------------------------------------------
1 | # See https://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file
2 |
--------------------------------------------------------------------------------
/storage/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/abbasikov/Rails-frontend-test/0497c2ac2853f300ba20419e89a96a08cc686c9a/storage/.keep
--------------------------------------------------------------------------------
/storage/development.sqlite3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/abbasikov/Rails-frontend-test/0497c2ac2853f300ba20419e89a96a08cc686c9a/storage/development.sqlite3
--------------------------------------------------------------------------------
/storage/development.sqlite3-shm:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/abbasikov/Rails-frontend-test/0497c2ac2853f300ba20419e89a96a08cc686c9a/storage/development.sqlite3-shm
--------------------------------------------------------------------------------
/storage/development.sqlite3-wal:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/abbasikov/Rails-frontend-test/0497c2ac2853f300ba20419e89a96a08cc686c9a/storage/development.sqlite3-wal
--------------------------------------------------------------------------------
/test/application_system_test_case.rb:
--------------------------------------------------------------------------------
1 | require "test_helper"
2 |
3 | class ApplicationSystemTestCase < ActionDispatch::SystemTestCase
4 | driven_by :selenium, using: :chrome, screen_size: [1400, 1400]
5 | end
6 |
--------------------------------------------------------------------------------
/test/controllers/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/abbasikov/Rails-frontend-test/0497c2ac2853f300ba20419e89a96a08cc686c9a/test/controllers/.keep
--------------------------------------------------------------------------------
/test/controllers/storefronts_controller_test.rb:
--------------------------------------------------------------------------------
1 | require "test_helper"
2 |
3 | class StorefrontsControllerTest < ActionDispatch::IntegrationTest
4 | setup do
5 | @storefront = storefronts(:one)
6 | end
7 |
8 | test "should get index" do
9 | get storefronts_url
10 | assert_response :success
11 | end
12 |
13 | test "should get new" do
14 | get new_storefront_url
15 | assert_response :success
16 | end
17 |
18 | test "should create storefront" do
19 | assert_difference("Storefront.count") do
20 | post storefronts_url, params: { storefront: { } }
21 | end
22 |
23 | assert_redirected_to storefront_url(Storefront.last)
24 | end
25 |
26 | test "should show storefront" do
27 | get storefront_url(@storefront)
28 | assert_response :success
29 | end
30 |
31 | test "should get edit" do
32 | get edit_storefront_url(@storefront)
33 | assert_response :success
34 | end
35 |
36 | test "should update storefront" do
37 | patch storefront_url(@storefront), params: { storefront: { } }
38 | assert_redirected_to storefront_url(@storefront)
39 | end
40 |
41 | test "should destroy storefront" do
42 | assert_difference("Storefront.count", -1) do
43 | delete storefront_url(@storefront)
44 | end
45 |
46 | assert_redirected_to storefronts_url
47 | end
48 | end
49 |
--------------------------------------------------------------------------------
/test/fixtures/files/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/abbasikov/Rails-frontend-test/0497c2ac2853f300ba20419e89a96a08cc686c9a/test/fixtures/files/.keep
--------------------------------------------------------------------------------
/test/fixtures/reasons.yml:
--------------------------------------------------------------------------------
1 | # Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html
2 |
3 | one:
4 | storefront: one
5 | code: MyString
6 | label: MyString
7 | restricted_resolution_types:
8 | active: false
9 | ordering: 1
10 |
11 | two:
12 | storefront: two
13 | code: MyString
14 | label: MyString
15 | restricted_resolution_types:
16 | active: false
17 | ordering: 1
18 |
--------------------------------------------------------------------------------
/test/fixtures/storefronts.yml:
--------------------------------------------------------------------------------
1 | # Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html
2 |
3 | # This model initially had no columns defined. If you add columns to the
4 | # model remove the "{}" from the fixture names and add the columns immediately
5 | # below each fixture, per the syntax in the comments below
6 | #
7 | one: {}
8 | # column: value
9 | #
10 | two: {}
11 | # column: value
12 |
--------------------------------------------------------------------------------
/test/helpers/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/abbasikov/Rails-frontend-test/0497c2ac2853f300ba20419e89a96a08cc686c9a/test/helpers/.keep
--------------------------------------------------------------------------------
/test/integration/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/abbasikov/Rails-frontend-test/0497c2ac2853f300ba20419e89a96a08cc686c9a/test/integration/.keep
--------------------------------------------------------------------------------
/test/models/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/abbasikov/Rails-frontend-test/0497c2ac2853f300ba20419e89a96a08cc686c9a/test/models/.keep
--------------------------------------------------------------------------------
/test/models/reason_test.rb:
--------------------------------------------------------------------------------
1 | require "test_helper"
2 |
3 | class ReasonTest < ActiveSupport::TestCase
4 | # test "the truth" do
5 | # assert true
6 | # end
7 | end
8 |
--------------------------------------------------------------------------------
/test/models/storefront_test.rb:
--------------------------------------------------------------------------------
1 | require "test_helper"
2 |
3 | class StorefrontTest < ActiveSupport::TestCase
4 | # test "the truth" do
5 | # assert true
6 | # end
7 | end
8 |
--------------------------------------------------------------------------------
/test/system/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/abbasikov/Rails-frontend-test/0497c2ac2853f300ba20419e89a96a08cc686c9a/test/system/.keep
--------------------------------------------------------------------------------
/test/system/storefronts_test.rb:
--------------------------------------------------------------------------------
1 | require "application_system_test_case"
2 |
3 | class StorefrontsTest < ApplicationSystemTestCase
4 | setup do
5 | @storefront = storefronts(:one)
6 | end
7 |
8 | test "visiting the index" do
9 | visit storefronts_url
10 | assert_selector "h1", text: "Storefronts"
11 | end
12 |
13 | test "should create storefront" do
14 | visit storefronts_url
15 | click_on "New storefront"
16 |
17 | click_on "Create Storefront"
18 |
19 | assert_text "Storefront was successfully created"
20 | click_on "Back"
21 | end
22 |
23 | test "should update Storefront" do
24 | visit storefront_url(@storefront)
25 | click_on "Edit this storefront", match: :first
26 |
27 | click_on "Update Storefront"
28 |
29 | assert_text "Storefront was successfully updated"
30 | click_on "Back"
31 | end
32 |
33 | test "should destroy Storefront" do
34 | visit storefront_url(@storefront)
35 | click_on "Destroy this storefront", match: :first
36 |
37 | assert_text "Storefront was successfully destroyed"
38 | end
39 | end
40 |
--------------------------------------------------------------------------------
/test/test_helper.rb:
--------------------------------------------------------------------------------
1 | ENV["RAILS_ENV"] ||= "test"
2 | require_relative "../config/environment"
3 | require "rails/test_help"
4 |
5 | module ActiveSupport
6 | class TestCase
7 | # Run tests in parallel with specified workers
8 | parallelize(workers: :number_of_processors)
9 |
10 | # Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order.
11 | fixtures :all
12 |
13 | # Add more helper methods to be used by all tests here...
14 | end
15 | end
16 |
--------------------------------------------------------------------------------
/tmp/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/abbasikov/Rails-frontend-test/0497c2ac2853f300ba20419e89a96a08cc686c9a/tmp/.keep
--------------------------------------------------------------------------------
/tmp/pids/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/abbasikov/Rails-frontend-test/0497c2ac2853f300ba20419e89a96a08cc686c9a/tmp/pids/.keep
--------------------------------------------------------------------------------
/tmp/storage/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/abbasikov/Rails-frontend-test/0497c2ac2853f300ba20419e89a96a08cc686c9a/tmp/storage/.keep
--------------------------------------------------------------------------------
/vendor/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/abbasikov/Rails-frontend-test/0497c2ac2853f300ba20419e89a96a08cc686c9a/vendor/.keep
--------------------------------------------------------------------------------
/vendor/javascript/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/abbasikov/Rails-frontend-test/0497c2ac2853f300ba20419e89a96a08cc686c9a/vendor/javascript/.keep
--------------------------------------------------------------------------------