Add games to seats and implement tables
This commit is contained in:
parent
32194b11b9
commit
92f2806e31
160
Gemfile.lock
160
Gemfile.lock
@ -34,12 +34,10 @@ GEM
|
|||||||
minitest (~> 5.1)
|
minitest (~> 5.1)
|
||||||
thread_safe (~> 0.1)
|
thread_safe (~> 0.1)
|
||||||
tzinfo (~> 1.1)
|
tzinfo (~> 1.1)
|
||||||
addressable (2.3.8)
|
addressable (2.4.0)
|
||||||
arel (5.0.1.20140414130214)
|
arel (5.0.1.20140414130214)
|
||||||
ast (2.1.0)
|
ast (2.2.0)
|
||||||
astrolabe (1.3.1)
|
babel-source (5.8.35)
|
||||||
parser (~> 2.2)
|
|
||||||
babel-source (5.8.26)
|
|
||||||
babel-transpiler (0.7.0)
|
babel-transpiler (0.7.0)
|
||||||
babel-source (>= 4.0, < 6)
|
babel-source (>= 4.0, < 6)
|
||||||
execjs (~> 2.0)
|
execjs (~> 2.0)
|
||||||
@ -62,25 +60,26 @@ GEM
|
|||||||
capistrano (>= 3.0.0)
|
capistrano (>= 3.0.0)
|
||||||
capistrano-postgresql (4.2.1)
|
capistrano-postgresql (4.2.1)
|
||||||
capistrano (>= 3.0)
|
capistrano (>= 3.0)
|
||||||
capistrano-rails (1.1.5)
|
capistrano-rails (1.1.6)
|
||||||
capistrano (~> 3.1)
|
capistrano (~> 3.1)
|
||||||
capistrano-bundler (~> 1.1)
|
capistrano-bundler (~> 1.1)
|
||||||
capistrano-rails-console (1.0.0)
|
capistrano-rails-console (1.0.2)
|
||||||
capistrano (>= 3.1.0, < 4.0.0)
|
capistrano (>= 3.1.0, < 4.0.0)
|
||||||
capistrano-rbenv (2.0.3)
|
capistrano-rbenv (2.0.4)
|
||||||
capistrano (~> 3.1)
|
capistrano (~> 3.1)
|
||||||
sshkit (~> 1.3)
|
sshkit (~> 1.3)
|
||||||
capistrano3-puma (1.2.1)
|
capistrano3-puma (1.2.1)
|
||||||
capistrano (~> 3.0)
|
capistrano (~> 3.0)
|
||||||
puma (>= 2.6)
|
puma (>= 2.6)
|
||||||
capybara (2.5.0)
|
capybara (2.6.2)
|
||||||
|
addressable
|
||||||
mime-types (>= 1.16)
|
mime-types (>= 1.16)
|
||||||
nokogiri (>= 1.3.3)
|
nokogiri (>= 1.3.3)
|
||||||
rack (>= 1.0.0)
|
rack (>= 1.0.0)
|
||||||
rack-test (>= 0.5.4)
|
rack-test (>= 0.5.4)
|
||||||
xpath (~> 2.0)
|
xpath (~> 2.0)
|
||||||
chartkick (1.4.1)
|
chartkick (1.4.1)
|
||||||
childprocess (0.5.6)
|
childprocess (0.5.9)
|
||||||
ffi (~> 1.0, >= 1.0.11)
|
ffi (~> 1.0, >= 1.0.11)
|
||||||
cliver (0.3.2)
|
cliver (0.3.2)
|
||||||
coderay (1.1.0)
|
coderay (1.1.0)
|
||||||
@ -90,38 +89,37 @@ GEM
|
|||||||
coffee-script (2.4.1)
|
coffee-script (2.4.1)
|
||||||
coffee-script-source
|
coffee-script-source
|
||||||
execjs
|
execjs
|
||||||
coffee-script-source (1.9.1.1)
|
coffee-script-source (1.10.0)
|
||||||
colorize (0.7.7)
|
|
||||||
connection_pool (2.2.0)
|
connection_pool (2.2.0)
|
||||||
database_cleaner (1.5.1)
|
database_cleaner (1.5.1)
|
||||||
debug_inspector (0.0.2)
|
debug_inspector (0.0.2)
|
||||||
devise (3.5.2)
|
devise (3.5.6)
|
||||||
bcrypt (~> 3.0)
|
bcrypt (~> 3.0)
|
||||||
orm_adapter (~> 0.1)
|
orm_adapter (~> 0.1)
|
||||||
railties (>= 3.2.6, < 5)
|
railties (>= 3.2.6, < 5)
|
||||||
responders
|
responders
|
||||||
thread_safe (~> 0.1)
|
thread_safe (~> 0.1)
|
||||||
warden (~> 1.2.3)
|
warden (~> 1.2.3)
|
||||||
devise_invitable (1.5.3)
|
devise_invitable (1.5.5)
|
||||||
actionmailer (>= 3.2.6, < 5)
|
actionmailer (>= 3.2.6, < 5)
|
||||||
devise (>= 3.2.0)
|
devise (>= 3.2.0)
|
||||||
diff-lcs (1.2.5)
|
diff-lcs (1.2.5)
|
||||||
dotenv (2.0.2)
|
dotenv (2.1.0)
|
||||||
dotenv-rails (2.0.2)
|
dotenv-rails (2.1.0)
|
||||||
dotenv (= 2.0.2)
|
dotenv (= 2.1.0)
|
||||||
railties (~> 4.0)
|
railties (>= 4.0, < 5.1)
|
||||||
em-websocket (0.5.1)
|
em-websocket (0.5.1)
|
||||||
eventmachine (>= 0.12.9)
|
eventmachine (>= 0.12.9)
|
||||||
http_parser.rb (~> 0.6.0)
|
http_parser.rb (~> 0.6.0)
|
||||||
erubis (2.7.0)
|
erubis (2.7.0)
|
||||||
eventmachine (1.0.8)
|
eventmachine (1.0.9.1)
|
||||||
execjs (2.6.0)
|
execjs (2.6.0)
|
||||||
factory_girl (4.5.0)
|
factory_girl (4.5.0)
|
||||||
activesupport (>= 3.0.0)
|
activesupport (>= 3.0.0)
|
||||||
factory_girl_rails (4.5.0)
|
factory_girl_rails (4.6.0)
|
||||||
factory_girl (~> 4.5.0)
|
factory_girl (~> 4.5.0)
|
||||||
railties (>= 3.0.0)
|
railties (>= 3.0.0)
|
||||||
faker (1.5.0)
|
faker (1.6.1)
|
||||||
i18n (~> 0.5)
|
i18n (~> 0.5)
|
||||||
ffi (1.9.10)
|
ffi (1.9.10)
|
||||||
formatador (0.2.5)
|
formatador (0.2.5)
|
||||||
@ -142,7 +140,7 @@ GEM
|
|||||||
guard-ctags-bundler (1.4.0)
|
guard-ctags-bundler (1.4.0)
|
||||||
guard (>= 2.0)
|
guard (>= 2.0)
|
||||||
guard-compat (>= 0.1.0)
|
guard-compat (>= 0.1.0)
|
||||||
guard-livereload (2.5.1)
|
guard-livereload (2.5.2)
|
||||||
em-websocket (~> 0.5)
|
em-websocket (~> 0.5)
|
||||||
guard (~> 2.8)
|
guard (~> 2.8)
|
||||||
guard-compat (~> 1.0)
|
guard-compat (~> 1.0)
|
||||||
@ -177,8 +175,8 @@ GEM
|
|||||||
hub (1.12.4)
|
hub (1.12.4)
|
||||||
i18n (0.7.0)
|
i18n (0.7.0)
|
||||||
interception (0.5)
|
interception (0.5)
|
||||||
jbuilder (2.3.2)
|
jbuilder (2.4.1)
|
||||||
activesupport (>= 3.0.0, < 5)
|
activesupport (>= 3.0.0, < 5.1)
|
||||||
multi_json (~> 1.2)
|
multi_json (~> 1.2)
|
||||||
jquery-rails (3.1.4)
|
jquery-rails (3.1.4)
|
||||||
railties (>= 3.0, < 5.0)
|
railties (>= 3.0, < 5.0)
|
||||||
@ -189,37 +187,37 @@ GEM
|
|||||||
activesupport (>= 3.0.0)
|
activesupport (>= 3.0.0)
|
||||||
launchy (2.4.3)
|
launchy (2.4.3)
|
||||||
addressable (~> 2.3)
|
addressable (~> 2.3)
|
||||||
listen (3.0.3)
|
listen (3.0.6)
|
||||||
rb-fsevent (>= 0.9.3)
|
rb-fsevent (>= 0.9.3)
|
||||||
rb-inotify (>= 0.9)
|
rb-inotify (>= 0.9.7)
|
||||||
lumberjack (1.0.9)
|
lumberjack (1.0.10)
|
||||||
mail (2.6.3)
|
mail (2.6.3)
|
||||||
mime-types (>= 1.16, < 3)
|
mime-types (>= 1.16, < 3)
|
||||||
method_source (0.8.2)
|
method_source (0.8.2)
|
||||||
mime-types (2.6.2)
|
mime-types (2.99)
|
||||||
mini_portile (0.6.2)
|
mini_portile2 (2.0.0)
|
||||||
minitest (5.8.1)
|
minitest (5.8.4)
|
||||||
multi_json (1.11.2)
|
multi_json (1.11.2)
|
||||||
nenv (0.2.0)
|
nenv (0.3.0)
|
||||||
net-scp (1.2.1)
|
net-scp (1.2.1)
|
||||||
net-ssh (>= 2.6.5)
|
net-ssh (>= 2.6.5)
|
||||||
net-ssh (3.0.1)
|
net-ssh (3.0.2)
|
||||||
newrelic_rpm (3.14.1.311)
|
newrelic_rpm (3.14.3.313)
|
||||||
nokogiri (1.6.6.2)
|
nokogiri (1.6.7.2)
|
||||||
mini_portile (~> 0.6.0)
|
mini_portile2 (~> 2.0.0.rc2)
|
||||||
notiffany (0.0.8)
|
notiffany (0.0.8)
|
||||||
nenv (~> 0.1)
|
nenv (~> 0.1)
|
||||||
shellany (~> 0.0)
|
shellany (~> 0.0)
|
||||||
orm_adapter (0.5.0)
|
orm_adapter (0.5.0)
|
||||||
parser (2.2.3.0)
|
parser (2.3.0.5)
|
||||||
ast (>= 1.1, < 3.0)
|
ast (~> 2.2)
|
||||||
pg (0.18.3)
|
pg (0.18.4)
|
||||||
poltergeist (1.7.0)
|
poltergeist (1.9.0)
|
||||||
capybara (~> 2.1)
|
capybara (~> 2.1)
|
||||||
cliver (~> 0.3.1)
|
cliver (~> 0.3.1)
|
||||||
multi_json (~> 1.0)
|
multi_json (~> 1.0)
|
||||||
websocket-driver (>= 0.2.0)
|
websocket-driver (>= 0.2.0)
|
||||||
polyamorous (1.2.0)
|
polyamorous (1.3.0)
|
||||||
activerecord (>= 3.0)
|
activerecord (>= 3.0)
|
||||||
powerpack (0.1.1)
|
powerpack (0.1.1)
|
||||||
pry (0.10.3)
|
pry (0.10.3)
|
||||||
@ -231,8 +229,8 @@ GEM
|
|||||||
pry-rescue (1.4.2)
|
pry-rescue (1.4.2)
|
||||||
interception (>= 0.5)
|
interception (>= 0.5)
|
||||||
pry
|
pry
|
||||||
puma (2.14.0)
|
puma (2.16.0)
|
||||||
pundit (1.0.1)
|
pundit (1.1.0)
|
||||||
activesupport (>= 3.0.0)
|
activesupport (>= 3.0.0)
|
||||||
quiet_assets (1.1.0)
|
quiet_assets (1.1.0)
|
||||||
railties (>= 3.1, < 5.0)
|
railties (>= 3.1, < 5.0)
|
||||||
@ -251,14 +249,14 @@ GEM
|
|||||||
bundler (>= 1.3.0, < 2.0)
|
bundler (>= 1.3.0, < 2.0)
|
||||||
railties (= 4.1.8)
|
railties (= 4.1.8)
|
||||||
sprockets-rails (~> 2.0)
|
sprockets-rails (~> 2.0)
|
||||||
rails_layout (1.0.26)
|
rails_layout (1.0.29)
|
||||||
railties (4.1.8)
|
railties (4.1.8)
|
||||||
actionpack (= 4.1.8)
|
actionpack (= 4.1.8)
|
||||||
activesupport (= 4.1.8)
|
activesupport (= 4.1.8)
|
||||||
rake (>= 0.8.7)
|
rake (>= 0.8.7)
|
||||||
thor (>= 0.18.1, < 2.0)
|
thor (>= 0.18.1, < 2.0)
|
||||||
rainbow (2.0.0)
|
rainbow (2.1.0)
|
||||||
rake (10.4.2)
|
rake (10.5.0)
|
||||||
ransack (1.7.0)
|
ransack (1.7.0)
|
||||||
actionpack (>= 3.0)
|
actionpack (>= 3.0)
|
||||||
activerecord (>= 3.0)
|
activerecord (>= 3.0)
|
||||||
@ -267,53 +265,53 @@ GEM
|
|||||||
polyamorous (~> 1.2)
|
polyamorous (~> 1.2)
|
||||||
rb-fchange (0.0.6)
|
rb-fchange (0.0.6)
|
||||||
ffi
|
ffi
|
||||||
rb-fsevent (0.9.6)
|
rb-fsevent (0.9.7)
|
||||||
rb-inotify (0.9.5)
|
rb-inotify (0.9.7)
|
||||||
ffi (>= 0.5.0)
|
ffi (>= 0.5.0)
|
||||||
rdoc (4.2.0)
|
rdoc (4.2.2)
|
||||||
json (~> 1.4)
|
json (~> 1.4)
|
||||||
react-rails (1.3.2)
|
react-rails (1.6.0)
|
||||||
babel-transpiler (>= 0.7.0)
|
babel-transpiler (>= 0.7.0)
|
||||||
coffee-script-source (~> 1.8)
|
coffee-script-source (~> 1.8)
|
||||||
connection_pool
|
connection_pool
|
||||||
execjs
|
execjs
|
||||||
rails (>= 3.2)
|
rails (>= 3.2)
|
||||||
tilt
|
tilt
|
||||||
react-rails-hot-loader (0.4.0)
|
react-rails-hot-loader (0.5.0)
|
||||||
em-websocket
|
em-websocket
|
||||||
rails
|
rails
|
||||||
react-rails
|
react-rails
|
||||||
responders (1.1.2)
|
responders (1.1.2)
|
||||||
railties (>= 3.2, < 4.2)
|
railties (>= 3.2, < 4.2)
|
||||||
rspec (3.3.0)
|
rspec (3.4.0)
|
||||||
rspec-core (~> 3.3.0)
|
rspec-core (~> 3.4.0)
|
||||||
rspec-expectations (~> 3.3.0)
|
rspec-expectations (~> 3.4.0)
|
||||||
rspec-mocks (~> 3.3.0)
|
rspec-mocks (~> 3.4.0)
|
||||||
rspec-core (3.3.2)
|
rspec-core (3.4.2)
|
||||||
rspec-support (~> 3.3.0)
|
rspec-support (~> 3.4.0)
|
||||||
rspec-expectations (3.3.1)
|
rspec-expectations (3.4.0)
|
||||||
diff-lcs (>= 1.2.0, < 2.0)
|
diff-lcs (>= 1.2.0, < 2.0)
|
||||||
rspec-support (~> 3.3.0)
|
rspec-support (~> 3.4.0)
|
||||||
rspec-mocks (3.3.2)
|
rspec-mocks (3.4.1)
|
||||||
diff-lcs (>= 1.2.0, < 2.0)
|
diff-lcs (>= 1.2.0, < 2.0)
|
||||||
rspec-support (~> 3.3.0)
|
rspec-support (~> 3.4.0)
|
||||||
rspec-rails (3.3.3)
|
rspec-rails (3.4.2)
|
||||||
actionpack (>= 3.0, < 4.3)
|
actionpack (>= 3.0, < 4.3)
|
||||||
activesupport (>= 3.0, < 4.3)
|
activesupport (>= 3.0, < 4.3)
|
||||||
railties (>= 3.0, < 4.3)
|
railties (>= 3.0, < 4.3)
|
||||||
rspec-core (~> 3.3.0)
|
rspec-core (~> 3.4.0)
|
||||||
rspec-expectations (~> 3.3.0)
|
rspec-expectations (~> 3.4.0)
|
||||||
rspec-mocks (~> 3.3.0)
|
rspec-mocks (~> 3.4.0)
|
||||||
rspec-support (~> 3.3.0)
|
rspec-support (~> 3.4.0)
|
||||||
rspec-support (3.3.0)
|
rspec-support (3.4.1)
|
||||||
rubocop (0.34.2)
|
rubocop (0.37.2)
|
||||||
astrolabe (~> 1.3)
|
parser (>= 2.3.0.4, < 3.0)
|
||||||
parser (>= 2.2.2.5, < 3.0)
|
|
||||||
powerpack (~> 0.1)
|
powerpack (~> 0.1)
|
||||||
rainbow (>= 1.99.1, < 3.0)
|
rainbow (>= 1.99.1, < 3.0)
|
||||||
ruby-progressbar (~> 1.4)
|
ruby-progressbar (~> 1.7)
|
||||||
|
unicode-display_width (~> 0.3)
|
||||||
ruby-progressbar (1.7.5)
|
ruby-progressbar (1.7.5)
|
||||||
ruby_parser (3.7.1)
|
ruby_parser (3.7.3)
|
||||||
sexp_processor (~> 4.1)
|
sexp_processor (~> 4.1)
|
||||||
rubyzip (1.1.7)
|
rubyzip (1.1.7)
|
||||||
sass (3.2.19)
|
sass (3.2.19)
|
||||||
@ -325,18 +323,18 @@ GEM
|
|||||||
sdoc (0.4.1)
|
sdoc (0.4.1)
|
||||||
json (~> 1.7, >= 1.7.7)
|
json (~> 1.7, >= 1.7.7)
|
||||||
rdoc (~> 4.0)
|
rdoc (~> 4.0)
|
||||||
selenium-webdriver (2.48.1)
|
selenium-webdriver (2.52.0)
|
||||||
childprocess (~> 0.5)
|
childprocess (~> 0.5)
|
||||||
multi_json (~> 1.0)
|
multi_json (~> 1.0)
|
||||||
rubyzip (~> 1.0)
|
rubyzip (~> 1.0)
|
||||||
websocket (~> 1.0)
|
websocket (~> 1.0)
|
||||||
sexp_processor (4.6.0)
|
sexp_processor (4.6.1)
|
||||||
shellany (0.0.1)
|
shellany (0.0.1)
|
||||||
simple_form (3.2.0)
|
simple_form (3.2.1)
|
||||||
actionpack (~> 4.0)
|
actionpack (> 4, < 5.1)
|
||||||
activemodel (~> 4.0)
|
activemodel (> 4, < 5.1)
|
||||||
slop (3.6.0)
|
slop (3.6.0)
|
||||||
spring (1.4.0)
|
spring (1.6.3)
|
||||||
spring-commands-rspec (1.0.4)
|
spring-commands-rspec (1.0.4)
|
||||||
spring (>= 0.9.1)
|
spring (>= 0.9.1)
|
||||||
sprockets (2.12.4)
|
sprockets (2.12.4)
|
||||||
@ -348,8 +346,7 @@ GEM
|
|||||||
actionpack (>= 3.0)
|
actionpack (>= 3.0)
|
||||||
activesupport (>= 3.0)
|
activesupport (>= 3.0)
|
||||||
sprockets (>= 2.8, < 4.0)
|
sprockets (>= 2.8, < 4.0)
|
||||||
sshkit (1.7.1)
|
sshkit (1.8.1)
|
||||||
colorize (>= 0.7.0)
|
|
||||||
net-scp (>= 1.1.2)
|
net-scp (>= 1.1.2)
|
||||||
net-ssh (>= 2.8.0)
|
net-ssh (>= 2.8.0)
|
||||||
sysexits (1.2.0)
|
sysexits (1.2.0)
|
||||||
@ -363,6 +360,7 @@ GEM
|
|||||||
uglifier (2.7.2)
|
uglifier (2.7.2)
|
||||||
execjs (>= 0.3.0)
|
execjs (>= 0.3.0)
|
||||||
json (>= 1.8.0)
|
json (>= 1.8.0)
|
||||||
|
unicode-display_width (0.3.1)
|
||||||
upmin-admin (0.1.3)
|
upmin-admin (0.1.3)
|
||||||
chartkick
|
chartkick
|
||||||
haml (>= 3.0.0)
|
haml (>= 3.0.0)
|
||||||
@ -371,10 +369,10 @@ GEM
|
|||||||
rails
|
rails
|
||||||
ransack
|
ransack
|
||||||
sass-rails
|
sass-rails
|
||||||
warden (1.2.3)
|
warden (1.2.6)
|
||||||
rack (>= 1.0)
|
rack (>= 1.0)
|
||||||
websocket (1.2.2)
|
websocket (1.2.2)
|
||||||
websocket-driver (0.6.2)
|
websocket-driver (0.6.3)
|
||||||
websocket-extensions (>= 0.1.0)
|
websocket-extensions (>= 0.1.0)
|
||||||
websocket-extensions (0.1.2)
|
websocket-extensions (0.1.2)
|
||||||
xpath (2.0.0)
|
xpath (2.0.0)
|
||||||
|
|||||||
@ -50,9 +50,10 @@ end
|
|||||||
# * zeus: 'zeus rspec' (requires the server to be started separately)
|
# * zeus: 'zeus rspec' (requires the server to be started separately)
|
||||||
# * 'just' rspec: 'rspec'
|
# * 'just' rspec: 'rspec'
|
||||||
|
|
||||||
guard :rspec, cmd: "bundle exec spring rspec", all_after_pass: false, failed_mode: :focus do #
|
guard :rspec, cmd: "bundle exec spring rspec", all_after_pass: false do#, failed_mode: :focus
|
||||||
require "guard/rspec/dsl"
|
require "guard/rspec/dsl"
|
||||||
dsl = Guard::RSpec::Dsl.new(self)
|
dsl = Guard::RSpec::Dsl.new(self)
|
||||||
|
notification :off
|
||||||
|
|
||||||
# Feel free to open issues for suggestions and improvements
|
# Feel free to open issues for suggestions and improvements
|
||||||
|
|
||||||
|
|||||||
@ -38,6 +38,7 @@ end
|
|||||||
guard 'rails', host: '0.0.0.0' do
|
guard 'rails', host: '0.0.0.0' do
|
||||||
watch('Gemfile.lock')
|
watch('Gemfile.lock')
|
||||||
watch(%r{^(config|lib)/.*})
|
watch(%r{^(config|lib)/.*})
|
||||||
|
notification :off
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -4,6 +4,8 @@ Thirteen Tien Len
|
|||||||
TODO
|
TODO
|
||||||
----
|
----
|
||||||
|
|
||||||
|
- Refactor seat.jsx buttons in to a <form>.
|
||||||
|
|
||||||
- 1st 2nd 3rd place messages. End game message.
|
- 1st 2nd 3rd place messages. End game message.
|
||||||
|
|
||||||
- Tables to contain the games
|
- Tables to contain the games
|
||||||
@ -36,6 +38,12 @@ first play
|
|||||||
|
|
||||||
- Review attributions and license compliance
|
- Review attributions and license compliance
|
||||||
|
|
||||||
|
- TODO: Refactor guardfiles down to one file using `groups`
|
||||||
|
https://github.com/guard/guard/wiki/Guardfile-examples
|
||||||
|
|
||||||
|
- TODO: Move game logic out of game model / controller to module in
|
||||||
|
/lib/game_logic.rb e.g. https://github.com/adamof/rails-poker/tree/master/poker
|
||||||
|
|
||||||
## Proposed Schema
|
## Proposed Schema
|
||||||
|
|
||||||
Table
|
Table
|
||||||
|
|||||||
@ -16,5 +16,5 @@
|
|||||||
//= require react
|
//= require react
|
||||||
//= require react_ujs
|
//= require react_ujs
|
||||||
//= require components
|
//= require components
|
||||||
//= require react-rails-hot-loader
|
// require react-rails-hot-loader
|
||||||
//= require_tree .
|
//= require_tree .
|
||||||
|
|||||||
@ -57,7 +57,7 @@ function handleFlashMessagesHeader(node, xhr) {
|
|||||||
|
|
||||||
$(document).ready(function() {
|
$(document).ready(function() {
|
||||||
var dummy = new Array();
|
var dummy = new Array();
|
||||||
var flashDiv = React.render(<FlashMessages messages={dummy} />, $('#flash_messages')[0]);
|
var flashDiv = ReactDOM.render(<FlashMessages messages={dummy} />, $('#flash_messages')[0]);
|
||||||
|
|
||||||
$(document).ajaxComplete(function(event, xhr, settings) {
|
$(document).ajaxComplete(function(event, xhr, settings) {
|
||||||
handleFlashMessagesHeader(flashDiv, xhr);
|
handleFlashMessagesHeader(flashDiv, xhr);
|
||||||
|
|||||||
@ -5,10 +5,14 @@ var Game = React.createClass({
|
|||||||
title: React.PropTypes.string,
|
title: React.PropTypes.string,
|
||||||
players: React.PropTypes.array,
|
players: React.PropTypes.array,
|
||||||
id: React.PropTypes.number,
|
id: React.PropTypes.number,
|
||||||
url: React.PropTypes.string,
|
|
||||||
play_to_beat_string: React.PropTypes.string
|
play_to_beat_string: React.PropTypes.string
|
||||||
},
|
},
|
||||||
|
|
||||||
|
url: function() {
|
||||||
|
var url = "/games/" + this.props.id;
|
||||||
|
return url;
|
||||||
|
},
|
||||||
|
|
||||||
getInitialState: function() {
|
getInitialState: function() {
|
||||||
return {
|
return {
|
||||||
data: null,
|
data: null,
|
||||||
@ -22,7 +26,7 @@ var Game = React.createClass({
|
|||||||
},
|
},
|
||||||
|
|
||||||
loadGameFromServer: function() {
|
loadGameFromServer: function() {
|
||||||
$.getJSON(this.props.url, function(result) {
|
$.getJSON(this.url(), function(result) {
|
||||||
if (this.isMounted()) {
|
if (this.isMounted()) {
|
||||||
this.setState({ data: result });
|
this.setState({ data: result });
|
||||||
}
|
}
|
||||||
@ -35,8 +39,9 @@ var Game = React.createClass({
|
|||||||
},
|
},
|
||||||
|
|
||||||
handlePlayHandSubmit: function(card_ids) {
|
handlePlayHandSubmit: function(card_ids) {
|
||||||
|
console.log("Hello from handlePlayHandSubmit()");
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: this.props.url + '/play_hand',
|
url: this.url() + '/play_hand',
|
||||||
type: 'PATCH',
|
type: 'PATCH',
|
||||||
dataType: 'json',
|
dataType: 'json',
|
||||||
data: card_ids,
|
data: card_ids,
|
||||||
@ -45,14 +50,14 @@ var Game = React.createClass({
|
|||||||
this.loadGameFromServer();
|
this.loadGameFromServer();
|
||||||
}.bind(this),
|
}.bind(this),
|
||||||
error: function(xhr, status, err) {
|
error: function(xhr, status, err) {
|
||||||
console.error(this.props.url, status, err.toString());
|
console.error(this.url(), status, err.toString());
|
||||||
}.bind(this)
|
}.bind(this)
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
handleStart: function() {
|
handleStart: function() {
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: this.props.url + '/start',
|
url: this.url() + '/start',
|
||||||
type: 'POST',
|
type: 'POST',
|
||||||
dataType: 'json',
|
dataType: 'json',
|
||||||
complete: function (jqXHR, textStatus) {
|
complete: function (jqXHR, textStatus) {
|
||||||
@ -69,7 +74,7 @@ var Game = React.createClass({
|
|||||||
|
|
||||||
handleJoin: function() {
|
handleJoin: function() {
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: this.props.url + '/join',
|
url: this.url() + '/join',
|
||||||
type: 'POST',
|
type: 'POST',
|
||||||
dataType: 'json',
|
dataType: 'json',
|
||||||
complete: function (jqXHR, textStatus) {
|
complete: function (jqXHR, textStatus) {
|
||||||
@ -98,7 +103,7 @@ var Game = React.createClass({
|
|||||||
:
|
:
|
||||||
<section id='game-controls'>
|
<section id='game-controls'>
|
||||||
{/* TODO: If not joinable, show why. i.e. game full*/ }
|
{/* TODO: If not joinable, show why. i.e. game full*/ }
|
||||||
{this.state.data.is_joinable ? <button onClick={this.handleJoin}>Join</button> : null }
|
{/* TODO: DEPRECATED use seat sit instead this.state.data.is_joinable ? <button onClick={this.handleJoin}>Join</button> : null */}
|
||||||
{/* TODO: If not startable, show why. i.e. need more players */}
|
{/* TODO: If not startable, show why. i.e. need more players */}
|
||||||
<div id='start'>
|
<div id='start'>
|
||||||
{this.state.data.is_started ? null : <button onClick={this.handleStart} disabled={this.state.data.is_startable ? null : "disabled" }>Start</button>}
|
{this.state.data.is_started ? null : <button onClick={this.handleStart} disabled={this.state.data.is_startable ? null : "disabled" }>Start</button>}
|
||||||
@ -108,6 +113,8 @@ var Game = React.createClass({
|
|||||||
|
|
||||||
<PlayerList
|
<PlayerList
|
||||||
game={this.state.data}
|
game={this.state.data}
|
||||||
|
current_user={this.props.current_user}
|
||||||
|
onSeatSubmit={this.props.onSeatSubmit}
|
||||||
onPlayHandSubmit={this.handlePlayHandSubmit} />
|
onPlayHandSubmit={this.handlePlayHandSubmit} />
|
||||||
|
|
||||||
{this.state.data.winner_player_id ? "Winner: " + this.state.data.winner_player_id : null}
|
{this.state.data.winner_player_id ? "Winner: " + this.state.data.winner_player_id : null}
|
||||||
|
|||||||
@ -8,10 +8,10 @@ var Player = React.createClass({
|
|||||||
return (
|
return (
|
||||||
<div id={"player-" + this.props.id} className={"player " + (this.props.game.controlling_player_id == this.props.id ? 'has-control' : '')}>
|
<div id={"player-" + this.props.id} className={"player " + (this.props.game.controlling_player_id == this.props.id ? 'has-control' : '')}>
|
||||||
<div className='user-name'>{this.props.email || "Guest" + this.props.soft_token.substr(0,6)}</div>
|
<div className='user-name'>{this.props.email || "Guest" + this.props.soft_token.substr(0,6)}</div>
|
||||||
{this.props.game.is_started
|
{this.props.game.is_started ?
|
||||||
?
|
|
||||||
<div>Inventory count: {this.props.inventory_count}</div>
|
<div>Inventory count: {this.props.inventory_count}</div>
|
||||||
: null }
|
: null }
|
||||||
|
|
||||||
|
|
||||||
{/* Show player controls if player is owned by current_user */}
|
{/* Show player controls if player is owned by current_user */}
|
||||||
{(this.props.soft_token == this.props.game.current_user_soft_token) && (this.props.game.is_started == true)
|
{(this.props.soft_token == this.props.game.current_user_soft_token) && (this.props.game.is_started == true)
|
||||||
|
|||||||
@ -4,6 +4,7 @@ var PlayerList = React.createClass({
|
|||||||
game_id: React.PropTypes.number
|
game_id: React.PropTypes.number
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/* TODO: DEPRECATED playerNodes */
|
||||||
playerNodes: function() {
|
playerNodes: function() {
|
||||||
var playerList = this;
|
var playerList = this;
|
||||||
var playerNodes = this.props.game.players.map(function (player) {
|
var playerNodes = this.props.game.players.map(function (player) {
|
||||||
@ -23,15 +24,45 @@ var PlayerList = React.createClass({
|
|||||||
return (
|
return (
|
||||||
<div id="playerList">
|
<div id="playerList">
|
||||||
<div id="top">
|
<div id="top">
|
||||||
{this.playerNodes()[0]}
|
<div className="game-seat position-1">
|
||||||
|
{console.log("Hello from player_list.jsx")}
|
||||||
|
{console.log(this.props.onPlayHandSubmit)}
|
||||||
|
<Seat
|
||||||
|
{...this.props.game.seats[0]}
|
||||||
|
game={this.props.game}
|
||||||
|
onPlayHandSubmit={this.props.onPlayHandSubmit}
|
||||||
|
current_user={this.props.current_user}
|
||||||
|
onSeatSubmit={this.props.onSeatSubmit} />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="mid">
|
<div id="mid">
|
||||||
{this.playerNodes()[1]}
|
<div className="game-seat position-2">
|
||||||
|
<Seat
|
||||||
|
{...this.props.game.seats[1]}
|
||||||
|
game={this.props.game}
|
||||||
|
onPlayHandSubmit={this.props.onPlayHandSubmit}
|
||||||
|
current_user={this.props.current_user}
|
||||||
|
onSeatSubmit={this.props.onSeatSubmit} />
|
||||||
|
</div>
|
||||||
<div id="play-to-beat">Hand to beat: {this.props.game.play_to_beat_string}</div>
|
<div id="play-to-beat">Hand to beat: {this.props.game.play_to_beat_string}</div>
|
||||||
{this.playerNodes()[2]}
|
<div className="game-seat position-3">
|
||||||
|
<Seat
|
||||||
|
{...this.props.game.seats[2]}
|
||||||
|
game={this.props.game}
|
||||||
|
onPlayHandSubmit={this.props.onPlayHandSubmit}
|
||||||
|
current_user={this.props.current_user}
|
||||||
|
onSeatSubmit={this.props.onSeatSubmit} />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="bot">
|
<div id="bot">
|
||||||
{this.playerNodes()[3]}
|
<div className="game-seat position-4">
|
||||||
|
<Seat
|
||||||
|
{...this.props.game.seats[3]}
|
||||||
|
game={this.props.game}
|
||||||
|
onPlayHandSubmit={this.props.onPlayHandSubmit}
|
||||||
|
current_user={this.props.current_user}
|
||||||
|
onSeatSubmit={this.props.onSeatSubmit} />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -1,29 +1,68 @@
|
|||||||
var Seat = React.createClass({
|
var Seat = React.createClass({
|
||||||
|
|
||||||
onClick: function(e) {
|
isOccupied: function() {
|
||||||
// TODO: Sit at table
|
//TODO: create isOccupied logic
|
||||||
$.ajax({
|
return false;
|
||||||
url: window.location.pathname + '/sit',
|
},
|
||||||
type: 'POST',
|
|
||||||
dataType: 'json',
|
url: function() {
|
||||||
complete: function (jqXHR, textStatus) {
|
var url = "/seats/" + this.props.id + ".json"
|
||||||
// callback
|
return url;
|
||||||
},
|
},
|
||||||
success: function (data, textStatus, jqXHR) {
|
|
||||||
// success callback
|
sitClick: function(e) {
|
||||||
},
|
this.props.onSeatSubmit(this.props.id, 'sit');
|
||||||
error: function (jqXHR, textStatus, errorThrown) {
|
},
|
||||||
// error callback
|
|
||||||
}
|
standClick: function(e) {
|
||||||
});
|
this.props.onSeatSubmit(this.props.id, 'stand');
|
||||||
|
},
|
||||||
|
|
||||||
|
isAvailable: function() {
|
||||||
|
return this.props.user_display_name == null
|
||||||
|
},
|
||||||
|
|
||||||
|
sitButtonStyle: function() {
|
||||||
|
var style = {};
|
||||||
|
if(null != this.props.user_id == this.props.current_user.id)
|
||||||
|
style = { display: 'none'};
|
||||||
|
if(this.props.user_soft_token == this.props.current_user.soft_token)
|
||||||
|
style = { display: 'none'};
|
||||||
|
return style;
|
||||||
|
},
|
||||||
|
|
||||||
|
standButtonStyle: function() {
|
||||||
|
var style = { display: 'none'};
|
||||||
|
if(null != this.props.user_id == this.props.current_user.id)
|
||||||
|
style = {};
|
||||||
|
if(this.props.user_soft_token == this.props.current_user.soft_token)
|
||||||
|
style = {};
|
||||||
|
return style;
|
||||||
},
|
},
|
||||||
|
|
||||||
render: function() {
|
render: function() {
|
||||||
return (
|
return (
|
||||||
<button onClick={this.onClick}>
|
<div className='seat'>
|
||||||
Sit
|
<div className='seat-controls'>
|
||||||
</button>
|
<button
|
||||||
|
onClick={this.sitClick}
|
||||||
|
style={ this.sitButtonStyle() }
|
||||||
|
disabled={!this.isAvailable()} >
|
||||||
|
Sit
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
onClick={this.standClick}
|
||||||
|
style={ this.standButtonStyle() }>
|
||||||
|
Stand
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
{this.props.player ?
|
||||||
|
<Player
|
||||||
|
game={this.props.game}
|
||||||
|
onPlayHandSubmit={this.props.onPlayHandSubmit}
|
||||||
|
{...this.props.player} />
|
||||||
|
: "Empty" }
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|||||||
35
app/assets/javascripts/components/seat_list.js.jsx
Normal file
35
app/assets/javascripts/components/seat_list.js.jsx
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
var SeatList = React.createClass({
|
||||||
|
propTypes: {
|
||||||
|
seats: React.PropTypes.array
|
||||||
|
},
|
||||||
|
|
||||||
|
seatNodes: function() {
|
||||||
|
var onSeatSubmit = this.props.onSeatSubmit;
|
||||||
|
var current_user = this.props.current_user;
|
||||||
|
var seatNodes = this.props.seats.map(function(seat){
|
||||||
|
return (
|
||||||
|
<Seat
|
||||||
|
key={seat.id}
|
||||||
|
id={seat.id}
|
||||||
|
user_id={seat.user_id}
|
||||||
|
user_soft_token={seat.user_soft_token}
|
||||||
|
user_display_name={seat.user_display_name}
|
||||||
|
current_user={current_user}
|
||||||
|
onSeatSubmit={onSeatSubmit} />
|
||||||
|
)
|
||||||
|
})
|
||||||
|
return seatNodes;
|
||||||
|
},
|
||||||
|
|
||||||
|
render: function() {
|
||||||
|
return (
|
||||||
|
<div id="seatList">
|
||||||
|
{this.seatNodes()[0]}
|
||||||
|
{this.seatNodes()[1]}
|
||||||
|
{this.seatNodes()[2]}
|
||||||
|
{this.seatNodes()[3]}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
@ -14,7 +14,7 @@ var Table = React.createClass({
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
componentDidMount: function() {
|
loadTableFromServer: function() {
|
||||||
$.getJSON(this.props.url, function(result) {
|
$.getJSON(this.props.url, function(result) {
|
||||||
if (this.isMounted()) {
|
if (this.isMounted()) {
|
||||||
this.setState({ data: result });
|
this.setState({ data: result });
|
||||||
@ -22,6 +22,29 @@ var Table = React.createClass({
|
|||||||
}.bind(this));
|
}.bind(this));
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
|
componentDidMount: function() {
|
||||||
|
this.loadTableFromServer();
|
||||||
|
},
|
||||||
|
|
||||||
|
handleSeatSubmit: function(seat_id, action) {
|
||||||
|
console.log("handleSeatSubmit");
|
||||||
|
$.ajax({
|
||||||
|
url: window.location.pathname + '/seats/' + seat_id + '/' + action,
|
||||||
|
type: 'PATCH',
|
||||||
|
dataType: 'json',
|
||||||
|
success: function (data, textStatus, jqXHR) {
|
||||||
|
// success callback
|
||||||
|
console.log(data.message);
|
||||||
|
this.loadTableFromServer();
|
||||||
|
}.bind(this),
|
||||||
|
error: function (jqXHR, textStatus, errorThrown) {
|
||||||
|
// error callback
|
||||||
|
console.log(data.message);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
render: function() {
|
render: function() {
|
||||||
if (!this.state.data) {
|
if (!this.state.data) {
|
||||||
return <div>Loading...</div>;
|
return <div>Loading...</div>;
|
||||||
@ -29,10 +52,8 @@ var Table = React.createClass({
|
|||||||
return (
|
return (
|
||||||
<div id={"table-" + this.state.data.id}>
|
<div id={"table-" + this.state.data.id}>
|
||||||
<h1>{this.state.data.title}</h1>
|
<h1>{this.state.data.title}</h1>
|
||||||
<Seat />
|
{/* TODO: DEPRECATED seats are now rendered within games <SeatList current_user={this.state.data.current_user} seats={this.state.data.seats} onSeatSubmit={this.handleSeatSubmit} /> */}
|
||||||
<Seat />
|
<Game id={this.state.data.current_game_id} current_user={this.state.data.current_user} onSeatSubmit={this.handleSeatSubmit} />
|
||||||
<Seat />
|
|
||||||
<Seat />
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
3
app/assets/javascripts/seat.js.coffee
Normal file
3
app/assets/javascripts/seat.js.coffee
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# Place all the behaviors and hooks related to the matching controller here.
|
||||||
|
# All this logic will automatically be available in application.js.
|
||||||
|
# You can use CoffeeScript in this file: http://coffeescript.org/
|
||||||
3
app/assets/stylesheets/seat.css.scss
Normal file
3
app/assets/stylesheets/seat.css.scss
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
// Place all the styles related to the Seat controller here.
|
||||||
|
// They will automatically be included in application.css.
|
||||||
|
// You can use Sass (SCSS) here: http://sass-lang.com/
|
||||||
@ -4,11 +4,18 @@ class GamesController < ApplicationController
|
|||||||
respond_to :html, :json
|
respond_to :html, :json
|
||||||
|
|
||||||
def index
|
def index
|
||||||
@games = Game.all.order :id
|
if params[:table_id]
|
||||||
|
@table = Table.find(params[:table_id])
|
||||||
|
@games = @table.games
|
||||||
|
else
|
||||||
|
@games = Game.all.order :id
|
||||||
|
end
|
||||||
respond_with(@games)
|
respond_with(@games)
|
||||||
end
|
end
|
||||||
|
|
||||||
def show
|
def show
|
||||||
|
#TODO: Implement standalone games, without a table?
|
||||||
|
#redirect_to @game.table
|
||||||
respond_with(@game)
|
respond_with(@game)
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -98,7 +105,8 @@ class GamesController < ApplicationController
|
|||||||
def play_now
|
def play_now
|
||||||
# First joinable game or create new game
|
# First joinable game or create new game
|
||||||
@game = Game.play_now(current_user)
|
@game = Game.play_now(current_user)
|
||||||
@game.add_player_from_user current_user
|
@seats = @game.seats.order(:position).map {|s| s.occupied? ? nil : s}
|
||||||
|
@seats.compact.last.sit(current_user)
|
||||||
redirect_to @game
|
redirect_to @game
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
85
app/controllers/seats_controller.rb
Normal file
85
app/controllers/seats_controller.rb
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
class SeatsController < ApplicationController
|
||||||
|
before_action :set_seat, only: [:show, :edit, :update, :destroy, :sit, :stand]
|
||||||
|
|
||||||
|
respond_to :html, :json
|
||||||
|
|
||||||
|
# GET /seats
|
||||||
|
# GET /seats.json
|
||||||
|
def index
|
||||||
|
@seats = Seat.all
|
||||||
|
end
|
||||||
|
|
||||||
|
# GET /seats/1
|
||||||
|
# GET /seats/1.json
|
||||||
|
def show
|
||||||
|
end
|
||||||
|
|
||||||
|
# GET /seats/new
|
||||||
|
def new
|
||||||
|
@seat = Seat.new
|
||||||
|
end
|
||||||
|
|
||||||
|
# GET /seats/1/edit
|
||||||
|
def edit
|
||||||
|
end
|
||||||
|
|
||||||
|
# POST /seats
|
||||||
|
# POST /seats.json
|
||||||
|
def create
|
||||||
|
@seat = Seat.new(seat_params)
|
||||||
|
|
||||||
|
respond_to do |format|
|
||||||
|
if @seat.save
|
||||||
|
format.html { redirect_to @seat, notice: 'Seat was successfully created.' }
|
||||||
|
format.json { render :show, status: :created, location: @seat }
|
||||||
|
else
|
||||||
|
format.html { render :new }
|
||||||
|
format.json { render json: @seat.errors, status: :unprocessable_entity }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# PATCH/PUT /seats/1
|
||||||
|
# PATCH/PUT /seats/1.json
|
||||||
|
def update
|
||||||
|
respond_to do |format|
|
||||||
|
if @seat.update(seat_params)
|
||||||
|
format.html { redirect_to @seat, notice: 'Seat was successfully updated.' }
|
||||||
|
format.json { render :show, status: :ok, location: @seat }
|
||||||
|
else
|
||||||
|
format.html { render :edit }
|
||||||
|
format.json { render json: @seat.errors, status: :unprocessable_entity }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# DELETE /seats/1
|
||||||
|
# DELETE /seats/1.json
|
||||||
|
def destroy
|
||||||
|
@seat.destroy
|
||||||
|
respond_to do |format|
|
||||||
|
format.html { redirect_to seats_url, notice: 'Seat was successfully destroyed.' }
|
||||||
|
format.json { head :no_content }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# POST /seats/1
|
||||||
|
def sit
|
||||||
|
@message = @seat.sit current_user
|
||||||
|
end
|
||||||
|
|
||||||
|
def stand
|
||||||
|
@message = @seat.stand current_user
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
# Use callbacks to share common setup or constraints between actions.
|
||||||
|
def set_seat
|
||||||
|
@seat = Seat.find(params[:id])
|
||||||
|
end
|
||||||
|
|
||||||
|
# Never trust parameters from the scary internet, only allow the white list through.
|
||||||
|
def seat_params
|
||||||
|
params.require(:seat).permit(:position, :table_id, :user_id)
|
||||||
|
end
|
||||||
|
end
|
||||||
2
app/helpers/seat_helper.rb
Normal file
2
app/helpers/seat_helper.rb
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
module SeatHelper
|
||||||
|
end
|
||||||
@ -1,6 +1,7 @@
|
|||||||
# The game class
|
# The game class
|
||||||
class Game < ActiveRecord::Base
|
class Game < ActiveRecord::Base
|
||||||
belongs_to :table
|
belongs_to :table
|
||||||
|
has_many :seats
|
||||||
has_many :players, dependent: :destroy
|
has_many :players, dependent: :destroy
|
||||||
has_many :users, through: :players
|
has_many :users, through: :players
|
||||||
has_many :player_cards, through: :players
|
has_many :player_cards, through: :players
|
||||||
@ -8,10 +9,12 @@ class Game < ActiveRecord::Base
|
|||||||
has_one :controlling_player
|
has_one :controlling_player
|
||||||
belongs_to :play_to_beat
|
belongs_to :play_to_beat
|
||||||
accepts_nested_attributes_for :players
|
accepts_nested_attributes_for :players
|
||||||
validates :title, presence: true
|
#validates :title, presence: true
|
||||||
|
after_create :add_table
|
||||||
|
|
||||||
|
# Returns the newest joinable game or creates a new game if none are found
|
||||||
scope :play_now, lambda { |user|
|
scope :play_now, lambda { |user|
|
||||||
where(status:nil).joins("LEFT OUTER JOIN players ON players.game_id = games.id").group("games.id").having("count(players) < 4").first || Game.create(title: "Game " + user.soft_token[0..4])
|
where(status:nil).joins("LEFT OUTER JOIN players ON players.game_id = games.id").group("games.id").having("count(players) < 4").last || Game.create(title: "Game " + user.soft_token[0..4])
|
||||||
}
|
}
|
||||||
|
|
||||||
def start
|
def start
|
||||||
@ -72,14 +75,37 @@ class Game < ActiveRecord::Base
|
|||||||
new_player = self.players.create(user: user, soft_token: user.soft_token)
|
new_player = self.players.create(user: user, soft_token: user.soft_token)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def remove_player_from_user(user)
|
||||||
|
return false unless self.has_user? user
|
||||||
|
|
||||||
|
if self.players.exists?(user_id: user.id)
|
||||||
|
@player = self.players.find_by(user_id: user.id)
|
||||||
|
elsif self.players.exists?(soft_token: user.soft_token)
|
||||||
|
@player = self.players.find_by(soft_token: user.soft_token)
|
||||||
|
end
|
||||||
|
|
||||||
|
if @player
|
||||||
|
@player.destroy
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
def can_accomodate(user)
|
def can_accomodate(user)
|
||||||
!(already_has?(user) || full?)
|
!(already_has?(user) || full?)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
#TODO: Which has_user? method is better? Probably has_user?.
|
||||||
def already_has?(user)
|
def already_has?(user)
|
||||||
self.players.pluck(:user_id, :soft_token).flatten.compact.to_set.intersect? ([user.id, user.soft_token].to_set)
|
self.players.pluck(:user_id, :soft_token).flatten.compact.to_set.intersect? ([user.id, user.soft_token].to_set)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def has_user? user
|
||||||
|
return true if self.players.exists?(user_id: user.id)
|
||||||
|
return true if self.players.exists?(soft_token: user.soft_token)
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
def full?
|
def full?
|
||||||
players.count >= 4
|
players.count >= 4
|
||||||
end
|
end
|
||||||
@ -130,4 +156,12 @@ class Game < ActiveRecord::Base
|
|||||||
@inventory_counts.include? 0
|
@inventory_counts.include? 0
|
||||||
end
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def add_table
|
||||||
|
self.table ||= Table.create current_game_id: self.id
|
||||||
|
self.seats = self.table.seats
|
||||||
|
self.save
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@ -1,4 +1,52 @@
|
|||||||
class Seat < ActiveRecord::Base
|
class Seat < ActiveRecord::Base
|
||||||
belongs_to :table
|
belongs_to :table
|
||||||
|
belongs_to :game
|
||||||
belongs_to :user
|
belongs_to :user
|
||||||
|
|
||||||
|
def sit(current_user)
|
||||||
|
if self.occupied?
|
||||||
|
return "Error. Seat is occupied."
|
||||||
|
else
|
||||||
|
# Stand up from any other seats at this table
|
||||||
|
current_user.stand_from(self.table)
|
||||||
|
|
||||||
|
self.user_id = current_user.id
|
||||||
|
self.user_soft_token = current_user.soft_token
|
||||||
|
self.save
|
||||||
|
|
||||||
|
self.table.current_game.add_player_from_user(current_user)
|
||||||
|
return "Successfully sat."
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def stand(current_user)
|
||||||
|
unless self.occupied_by?(current_user)
|
||||||
|
return "Error. Seat not occupied by you."
|
||||||
|
else
|
||||||
|
self.user_id = nil
|
||||||
|
self.user_soft_token = nil
|
||||||
|
self.save
|
||||||
|
|
||||||
|
self.table.current_game.remove_player_from_user(current_user)
|
||||||
|
return "Successfully stood up."
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def occupied?
|
||||||
|
self.user_id.present? || self.user_soft_token.present?
|
||||||
|
end
|
||||||
|
|
||||||
|
def occupied_by? user
|
||||||
|
if user.id.present?
|
||||||
|
self.user_id == user.id
|
||||||
|
end
|
||||||
|
if user.soft_token.present?
|
||||||
|
self.user_soft_token == user.soft_token
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def user_display_name
|
||||||
|
return nil unless self.occupied?
|
||||||
|
self.user.try(:email) || "Guest" + self.user_soft_token.to_s[0..4]
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@ -3,5 +3,28 @@ class Table < ActiveRecord::Base
|
|||||||
has_many :seats
|
has_many :seats
|
||||||
has_many :users, through: :seats
|
has_many :users, through: :seats
|
||||||
has_many :games
|
has_many :games
|
||||||
has_one :current_game, :class_name => "Game", :primary_key => "current_game_id"
|
#TODO: Deprecated current_game_id from database.
|
||||||
|
# Instead calculate with self.current_game
|
||||||
|
#
|
||||||
|
#has_one :current_game, :class_name => "Game", :primary_key => "current_game_id"
|
||||||
|
|
||||||
|
#TODO: Should these be part of Game initialize instead of callback?
|
||||||
|
after_create :add_seats
|
||||||
|
after_create :add_game
|
||||||
|
|
||||||
|
def current_game
|
||||||
|
self.games.last
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def add_seats
|
||||||
|
1.upto(4) do |i|
|
||||||
|
self.seats.create(position: i)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def add_game
|
||||||
|
self.games.create if self.current_game_id.blank?
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@ -16,6 +16,25 @@ class User < ActiveRecord::Base
|
|||||||
!soft_user?
|
!soft_user?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def display_name
|
||||||
|
self.email || "Guest#{self.soft_token[0..5]}"
|
||||||
|
end
|
||||||
|
|
||||||
|
def stand_from(table)
|
||||||
|
@seats = []
|
||||||
|
if self.id
|
||||||
|
@seats << table.seats.where(user_id: self.id)
|
||||||
|
end
|
||||||
|
if self.soft_token
|
||||||
|
@seats << table.seats.where(user_soft_token: self.soft_token)
|
||||||
|
end
|
||||||
|
@seats.flatten.each do |seat|
|
||||||
|
seat.user_id = nil
|
||||||
|
seat.user_soft_token = nil
|
||||||
|
seat.save
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
# Include default devise modules. Others available are:
|
# Include default devise modules. Others available are:
|
||||||
# :confirmable, :lockable, :timeoutable and :omniauthable
|
# :confirmable, :lockable, :timeoutable and :omniauthable
|
||||||
devise :invitable, :database_authenticatable, :registerable, # :confirmable,
|
devise :invitable, :database_authenticatable, :registerable, # :confirmable,
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
#game-component-container-container= react_component 'Game', props = {url: "#{game_path @game}"}, html_options = {id: "game-component-container"}
|
#game-component-container-container= react_component 'Game', props = {id: @game.id, current_user: current_user}, html_options = {id: "game-component-container"}
|
||||||
|
|
||||||
-# TODO: Remove deprecated commented out code
|
-# TODO: Remove deprecated commented out code
|
||||||
-#%p
|
-#%p
|
||||||
|
|||||||
@ -13,14 +13,40 @@ json.is_startable @game.startable?
|
|||||||
json.current_user_id current_user.try(:id)
|
json.current_user_id current_user.try(:id)
|
||||||
json.current_user_soft_token current_user.try(:soft_token)
|
json.current_user_soft_token current_user.try(:soft_token)
|
||||||
|
|
||||||
json.players @game.players do |player|
|
#json.players @game.players do |player|
|
||||||
json.id player.id
|
# json.id player.id
|
||||||
json.email player.user.try(:email)
|
# json.email player.user.try(:email)
|
||||||
json.inventory_count player.inventory.count
|
# json.inventory_count player.inventory.count
|
||||||
json.user_id player.user.try(:id)
|
# json.user_id player.user.try(:id)
|
||||||
json.soft_token player.soft_token
|
# json.soft_token player.soft_token
|
||||||
|
#
|
||||||
|
# if player.soft_token == current_user.soft_token
|
||||||
|
# json.inventory player.inventory
|
||||||
|
# end
|
||||||
|
#end
|
||||||
|
|
||||||
if player.soft_token == current_user.soft_token
|
json.seats @game.seats.order(:position) do |seat|
|
||||||
json.inventory player.inventory
|
json.id seat.id
|
||||||
|
json.table_id seat.table_id
|
||||||
|
json.position seat.position
|
||||||
|
json.user_id seat.user_id
|
||||||
|
json.user_soft_token seat.user_soft_token
|
||||||
|
json.user_display_name seat.user_display_name
|
||||||
|
|
||||||
|
json.set! :player do
|
||||||
|
@player = nil
|
||||||
|
if !seat.user_id.blank?
|
||||||
|
@player = @game.players.find_by(user_id: seat.user_id)
|
||||||
|
elsif !seat.user_soft_token.blank?
|
||||||
|
@player = @game.players.find_by(soft_token: seat.user_soft_token)
|
||||||
|
end
|
||||||
|
if @player
|
||||||
|
json.id @player.id
|
||||||
|
json.email @player.user.try(:email)
|
||||||
|
json.inventory_count @player.inventory.count
|
||||||
|
json.user_id @player.user_id
|
||||||
|
json.soft_token @player.soft_token
|
||||||
|
json.inventory @player.inventory if @player.soft_token == current_user.soft_token
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
1
app/views/seats/show.json.jbuilder
Normal file
1
app/views/seats/show.json.jbuilder
Normal file
@ -0,0 +1 @@
|
|||||||
|
json.extract! @seat, :id, :table_id, :user_id, :user_soft_token
|
||||||
1
app/views/seats/sit.json.jbuilder
Normal file
1
app/views/seats/sit.json.jbuilder
Normal file
@ -0,0 +1 @@
|
|||||||
|
json.message @message
|
||||||
1
app/views/seats/stand.json.jbuilder
Normal file
1
app/views/seats/stand.json.jbuilder
Normal file
@ -0,0 +1 @@
|
|||||||
|
json.message @message
|
||||||
@ -1 +1,13 @@
|
|||||||
json.extract! @table, :id, :title, :created_at, :updated_at
|
json.extract! @table, :id, :title, :created_at, :updated_at
|
||||||
|
|
||||||
|
json.current_game_id @table.current_game.id
|
||||||
|
json.current_user current_user
|
||||||
|
|
||||||
|
json.seats @table.seats.order(:position) do |seat|
|
||||||
|
json.id seat.id
|
||||||
|
json.table_id seat.table_id
|
||||||
|
json.position seat.position
|
||||||
|
json.user_id seat.user_id
|
||||||
|
json.user_soft_token seat.user_soft_token
|
||||||
|
json.user_display_name seat.user_display_name
|
||||||
|
end
|
||||||
|
|||||||
@ -1,3 +1,3 @@
|
|||||||
if Rails.env.development?
|
if Rails.env.development?
|
||||||
React::Rails::HotLoader.start()
|
#React::Rails::HotLoader.start()
|
||||||
end
|
end
|
||||||
|
|||||||
@ -1,7 +1,12 @@
|
|||||||
Rails.application.routes.draw do
|
Rails.application.routes.draw do
|
||||||
resources :players
|
resources :players
|
||||||
resources :tables do
|
resources :tables do
|
||||||
resources :seats
|
resources :seats do
|
||||||
|
member do
|
||||||
|
patch 'sit'
|
||||||
|
patch 'stand'
|
||||||
|
end
|
||||||
|
end
|
||||||
resources :games
|
resources :games
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
5
db/migrate/20160209120734_add_position_to_seats.rb
Normal file
5
db/migrate/20160209120734_add_position_to_seats.rb
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
class AddPositionToSeats < ActiveRecord::Migration
|
||||||
|
def change
|
||||||
|
add_column :seats, :position, :integer
|
||||||
|
end
|
||||||
|
end
|
||||||
@ -0,0 +1,5 @@
|
|||||||
|
class AddUserSoftTokenToSeats < ActiveRecord::Migration
|
||||||
|
def change
|
||||||
|
add_column :seats, :user_soft_token, :string
|
||||||
|
end
|
||||||
|
end
|
||||||
5
db/migrate/20160219012611_add_game_id_to_seats.rb
Normal file
5
db/migrate/20160219012611_add_game_id_to_seats.rb
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
class AddGameIdToSeats < ActiveRecord::Migration
|
||||||
|
def change
|
||||||
|
add_column :seats, :game_id, :integer
|
||||||
|
end
|
||||||
|
end
|
||||||
@ -11,7 +11,7 @@
|
|||||||
#
|
#
|
||||||
# It's strongly recommended that you check this file into your version control system.
|
# It's strongly recommended that you check this file into your version control system.
|
||||||
|
|
||||||
ActiveRecord::Schema.define(version: 20151231035240) do
|
ActiveRecord::Schema.define(version: 20160219012611) do
|
||||||
|
|
||||||
# These are extensions that must be enabled in order to support this database
|
# These are extensions that must be enabled in order to support this database
|
||||||
enable_extension "plpgsql"
|
enable_extension "plpgsql"
|
||||||
@ -76,6 +76,9 @@ ActiveRecord::Schema.define(version: 20151231035240) do
|
|||||||
t.integer "user_id"
|
t.integer "user_id"
|
||||||
t.datetime "created_at"
|
t.datetime "created_at"
|
||||||
t.datetime "updated_at"
|
t.datetime "updated_at"
|
||||||
|
t.integer "position"
|
||||||
|
t.string "user_soft_token"
|
||||||
|
t.integer "game_id"
|
||||||
end
|
end
|
||||||
|
|
||||||
add_index "seats", ["table_id"], name: "index_seats_on_table_id", using: :btree
|
add_index "seats", ["table_id"], name: "index_seats_on_table_id", using: :btree
|
||||||
|
|||||||
@ -1,7 +1,10 @@
|
|||||||
FactoryGirl.define do
|
FactoryGirl.define do
|
||||||
factory :seat do
|
factory :seat do
|
||||||
table { FactoryGirl.create(:table) }
|
table { FactoryGirl.create(:table) }
|
||||||
user { FactoryGirl.create(:user) }
|
|
||||||
end
|
|
||||||
|
|
||||||
|
trait :occupied do
|
||||||
|
user { FactoryGirl.create(:user) }
|
||||||
|
user_soft_token { user.soft_token }
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
FactoryGirl.define do
|
FactoryGirl.define do
|
||||||
factory :table do
|
factory :table do
|
||||||
sequence(:title) { |n| "Test Table #{n}" }
|
sequence(:title) { |n| "Test Table #{n}" }
|
||||||
current_game { FactoryGirl.create(:game) }
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@ -3,7 +3,7 @@ FactoryGirl.define do
|
|||||||
confirmed_at Time.now
|
confirmed_at Time.now
|
||||||
name 'Test User'
|
name 'Test User'
|
||||||
sequence(:email) { |n| "test#{n}@example.com" }
|
sequence(:email) { |n| "test#{n}@example.com" }
|
||||||
password 'please123'
|
password 'password'
|
||||||
sequence(:soft_token) { |n| "soft_token#{n}" }
|
sequence(:soft_token) { |n| "soft_token#{n}" }
|
||||||
|
|
||||||
trait :admin do
|
trait :admin do
|
||||||
|
|||||||
@ -2,31 +2,68 @@
|
|||||||
# As a visitor
|
# As a visitor
|
||||||
# I want to quickly join a game
|
# I want to quickly join a game
|
||||||
# So I can play
|
# So I can play
|
||||||
feature 'Play now', :devise do
|
feature 'Play now', :devise, js: true do
|
||||||
before { @game = FactoryGirl.create :game }
|
|
||||||
# Scenario: Visitor can play now
|
# Scenario: Visitor can play now
|
||||||
# Given I am not signed in
|
# Given I am not signed in
|
||||||
# When I click Play Now
|
# When I click Play Now
|
||||||
# Then I join a game
|
# Then I join a game
|
||||||
scenario 'visitor can join a game', js: true do
|
describe 'visitor can Play Now' do
|
||||||
visit root_path
|
context 'there are no joinable games' do
|
||||||
click_link 'Play Now'
|
before do
|
||||||
expect(page).to have_content "Test Game"
|
expect(Game.all.count).to eq 0
|
||||||
expect(current_path).to eq game_path(@game)
|
visit root_path
|
||||||
@player = @game.players.last
|
click_link 'Play Now'
|
||||||
@playerComponent = page.find("#player-1")
|
end
|
||||||
expect(@playerComponent.text).to have_content("Guest#{@player.soft_token[0..5]}")
|
it 'creates and joins a new game' do
|
||||||
|
#TODO: Fix race condition
|
||||||
|
expect(page).to have_content "Hand to beat"
|
||||||
|
#Game title derived from visitor soft_token
|
||||||
|
expect(page).to have_content "#{Game.last.players.first.soft_token[0..4]}"
|
||||||
|
#Game count increased by 1
|
||||||
|
expect(Game.all.count).to eq 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
# Add another player
|
context 'visitor joins an existing game' do
|
||||||
@game.add_player_from_user FactoryGirl.create :user
|
before do
|
||||||
#TODO: Remove race condition
|
FactoryGirl.create :game
|
||||||
visit current_path
|
@game = Game.last
|
||||||
click_button 'Start'
|
visit root_path
|
||||||
#TODO: Remove race condition
|
expect(Game.all.count).to eq 1
|
||||||
visit current_path
|
click_link 'Play Now'
|
||||||
visit current_path
|
end
|
||||||
visit current_path
|
|
||||||
visit current_path
|
it 'shows and starts the game' do
|
||||||
expect(page).to have_content 'Inventory'
|
#TODO: Deprecated it shows the game title
|
||||||
|
#expect(page).to have_content "Test Game"
|
||||||
|
expect(page).to have_content "Hand to beat"
|
||||||
|
#it 'is located at the correct url' do
|
||||||
|
expect(current_path).to eq game_path(@game)
|
||||||
|
|
||||||
|
#it 'shows the visitor as a player' do
|
||||||
|
@player = @game.players.last
|
||||||
|
@playerComponent = page.find("#player-1")
|
||||||
|
#TODO: have_content @player.display_name
|
||||||
|
expect(@playerComponent.text).to have_content("Guest#{@player.soft_token[0..5]}")
|
||||||
|
|
||||||
|
#it 'shows other players' do
|
||||||
|
# Add another player
|
||||||
|
@user2 = FactoryGirl.create :user
|
||||||
|
@seats = @game.table.seats.map { |s| s.occupied? ? nil : s}
|
||||||
|
@seats.compact.first.sit(@user2)
|
||||||
|
#TODO: Remove race condition
|
||||||
|
visit current_path
|
||||||
|
expect(page).to have_content @user2.display_name
|
||||||
|
#it 'the game is startable' do
|
||||||
|
click_button 'Start'
|
||||||
|
#TODO: Remove race condition
|
||||||
|
visit current_path
|
||||||
|
visit current_path
|
||||||
|
visit current_path
|
||||||
|
visit current_path
|
||||||
|
expect(page).to have_content 'Inventory'
|
||||||
|
expect(Game.all.count).to eq 1
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@ -7,7 +7,7 @@ feature 'Play a hand', type: :feature, js: true do
|
|||||||
@game = setup_game
|
@game = setup_game
|
||||||
@game.reload
|
@game.reload
|
||||||
@player = @game.controlling_player
|
@player = @game.controlling_player
|
||||||
signin(@player.user.email,'please123')
|
signin(@player.user.email,'password')
|
||||||
#login_as(@player.user, scope: :user)
|
#login_as(@player.user, scope: :user)
|
||||||
visit game_path @game
|
visit game_path @game
|
||||||
end
|
end
|
||||||
@ -228,4 +228,17 @@ feature 'Play a hand', type: :feature, js: true do
|
|||||||
expect(page).to have_content 'Hand to beat: None'
|
expect(page).to have_content 'Hand to beat: None'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Scenario: Player wins the game
|
||||||
|
# Given I am the active player
|
||||||
|
# And I play my last card(s)
|
||||||
|
# And I am the first player to do so
|
||||||
|
# Then I see a 1st place winner message
|
||||||
|
scenario 'first place winner' do
|
||||||
|
# play last card
|
||||||
|
pending "TBD"
|
||||||
|
expect(@player.inventory.count).to eq 0
|
||||||
|
expect(page).to have_content "Winner: #{@player.display_name}"
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
108
spec/features/seats/seats_sit_spec.rb
Normal file
108
spec/features/seats/seats_sit_spec.rb
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
# Feature: Seats
|
||||||
|
# As a visitor
|
||||||
|
# I want to sit in a seat
|
||||||
|
# So I can be at a table and play a game
|
||||||
|
feature 'Seats', :devise, js: true do
|
||||||
|
context "As a visitor" do
|
||||||
|
before(:each) do
|
||||||
|
@table = FactoryGirl.create :table
|
||||||
|
visit table_path @table
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'visitor can sit in an empty seat' do
|
||||||
|
click_button 'Sit', match: :first
|
||||||
|
expect(page).to have_content "Guest"
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'sit button is disabled for unavailable seats' do
|
||||||
|
@button = page.find_button('Sit', match: :first)
|
||||||
|
@button.click
|
||||||
|
expect(page).to have_content "Guest"
|
||||||
|
expect(@button.disabled?).to eq true
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'has a stand button if current user is seated' do
|
||||||
|
@button = page.find_button('Sit', match: :first)
|
||||||
|
@button.click
|
||||||
|
expect(page).to have_content "Guest"
|
||||||
|
@buttons = page.find_all('button', text: 'Stand')
|
||||||
|
expect(@buttons.length).to eq 1
|
||||||
|
end
|
||||||
|
|
||||||
|
scenario 'table seats match up with game seats' do
|
||||||
|
click_button 'Sit', match: :first
|
||||||
|
expect(page.find(:css, ".game-seat.position-2")).to have_content "Guest"
|
||||||
|
end
|
||||||
|
|
||||||
|
#TODO: User can only occupy one seat per table
|
||||||
|
scenario 'visitor changes seats' do
|
||||||
|
click_button 'Sit', match: :first
|
||||||
|
expect(page).to have_content "Guest"
|
||||||
|
#TODO: Fix race condition
|
||||||
|
sleep 3
|
||||||
|
click_button 'Sit', match: :first
|
||||||
|
expect(page).to have_content "Guest"
|
||||||
|
expect(page.text.scan('Guest').count).to eq 2
|
||||||
|
end
|
||||||
|
|
||||||
|
scenario 'visitor can join the current game' do
|
||||||
|
click_button 'Sit', match: :first
|
||||||
|
#TODO: Fix race condition. Trigger game react component reload when player joins a table
|
||||||
|
sleep 4
|
||||||
|
expect(page).to have_content "Guest"
|
||||||
|
expect(page.text.scan('Guest').count).to eq 2
|
||||||
|
end
|
||||||
|
|
||||||
|
scenario 'visitor can leave the current game' do
|
||||||
|
click_button 'Sit', match: :first
|
||||||
|
#TODO: Fix race condition
|
||||||
|
sleep 4
|
||||||
|
expect(page.text.scan('Guest').count).to eq 2
|
||||||
|
click_button 'Stand', match: :first
|
||||||
|
expect(page).to have_content "Sit"
|
||||||
|
#TODO: Fix race condition
|
||||||
|
sleep 4
|
||||||
|
expect(page.text.scan('Guest').count).to eq 0
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
context "As a user" do
|
||||||
|
before(:each) do
|
||||||
|
@table = FactoryGirl.create :table
|
||||||
|
@user = FactoryGirl.create :user
|
||||||
|
signin(@user.email, @user.password)
|
||||||
|
visit table_path @table
|
||||||
|
end
|
||||||
|
|
||||||
|
scenario 'user can sit at the table' do
|
||||||
|
#TODO: Fix race condition
|
||||||
|
expect(page).to have_content "Sit"
|
||||||
|
click_button 'Sit', match: :first
|
||||||
|
expect(page).to have_content @user.email
|
||||||
|
end
|
||||||
|
|
||||||
|
scenario 'user can join the current game' do
|
||||||
|
expect(page).to have_content "Sit"
|
||||||
|
click_button 'Sit', match: :first
|
||||||
|
#TODO: Fix race condition. Trigger game react component reload when player joins a table
|
||||||
|
sleep 4
|
||||||
|
expect(page).to have_content @user.email
|
||||||
|
expect(page.text.scan(@user.email).count).to eq 2
|
||||||
|
end
|
||||||
|
|
||||||
|
scenario 'user can leave the current game' do
|
||||||
|
expect(page).to have_content "Sit"
|
||||||
|
click_button 'Sit', match: :first
|
||||||
|
#TODO: Fix race condition
|
||||||
|
sleep 4
|
||||||
|
expect(page.text.scan(@user.email).count).to eq 2
|
||||||
|
click_button 'Stand', match: :first
|
||||||
|
expect(page).to have_content "Sit"
|
||||||
|
#TODO: Fix race condition
|
||||||
|
sleep 4
|
||||||
|
expect(page.text.scan(@user.email).count).to eq 0
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
@ -26,7 +26,7 @@ feature 'Table index', :devise do
|
|||||||
# Then I see an index of tables
|
# Then I see an index of tables
|
||||||
scenario 'I can see all the tables', js: true do
|
scenario 'I can see all the tables', js: true do
|
||||||
@user = FactoryGirl.create :user
|
@user = FactoryGirl.create :user
|
||||||
signin(@user.email,'please123')
|
signin(@user.email,'password')
|
||||||
|
|
||||||
5.times { FactoryGirl.create :table }
|
5.times { FactoryGirl.create :table }
|
||||||
visit root_path
|
visit root_path
|
||||||
|
|||||||
@ -9,33 +9,70 @@ feature 'Table show', :devise do
|
|||||||
visit tables_path
|
visit tables_path
|
||||||
click_link @table.title
|
click_link @table.title
|
||||||
end
|
end
|
||||||
# Scenario: Visitor can view a table
|
|
||||||
# Given I am not signed in
|
|
||||||
# When I visit a table
|
|
||||||
# Then I see the table attributes
|
|
||||||
scenario 'visitor can see the table', js: true do
|
|
||||||
expect(page).to have_selector "#table-#{@table.id} > h1", @table.title
|
|
||||||
end
|
|
||||||
|
|
||||||
scenario 'visitor can sit at the table', js: true do
|
scenario 'visitor can sit at the table', js: true do
|
||||||
click_button 'Sit'
|
click_button 'Sit', match: :first
|
||||||
expect(page).to have_content "Guest"
|
expect(page).to have_content "Guest"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
scenario 'visitor can join the current game', js: true do
|
||||||
|
click_button 'Sit', match: :first
|
||||||
|
#TODO: Fix race condition. Trigger game react component reload when player joins a table
|
||||||
|
sleep 4
|
||||||
|
expect(page).to have_content "Guest"
|
||||||
|
expect(page.text.scan('Guest').count).to eq 2
|
||||||
|
end
|
||||||
|
|
||||||
|
scenario 'visitor can leave the current game', js: true do
|
||||||
|
click_button 'Sit', match: :first
|
||||||
|
#TODO: Fix race condition
|
||||||
|
sleep 4
|
||||||
|
expect(page.text.scan('Guest').count).to eq 2
|
||||||
|
click_button 'Stand', match: :first
|
||||||
|
expect(page).to have_content "Sit"
|
||||||
|
#TODO: Fix race condition
|
||||||
|
sleep 4
|
||||||
|
expect(page.text.scan('Guest').count).to eq 0
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
context "As a user" do
|
context "As a user" do
|
||||||
# Scenario: User can view a table
|
before(:each) do
|
||||||
# Given I am signed in
|
|
||||||
# When I click a table
|
|
||||||
# Then I see an index of tables
|
|
||||||
scenario 'visitor can see the table', js: true do
|
|
||||||
@table = FactoryGirl.create :table
|
@table = FactoryGirl.create :table
|
||||||
# TODO: sign in
|
@user = FactoryGirl.create :user
|
||||||
visit tables_path
|
signin(@user.email, @user.password)
|
||||||
click_link @table.title
|
visit table_path @table
|
||||||
expect(page).to have_button "Sit"
|
|
||||||
expect(page).to have_selector "#table-#{@table.id} > .title", @table.title
|
|
||||||
expect(current_path).to eq table_path(@table)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
scenario 'user can sit at the table', js: true do
|
||||||
|
#TODO: Fix race condition
|
||||||
|
expect(page).to have_content "Sit"
|
||||||
|
click_button 'Sit', match: :first
|
||||||
|
expect(page).to have_content @user.email
|
||||||
|
end
|
||||||
|
|
||||||
|
scenario 'user can join the current game', js: true do
|
||||||
|
expect(page).to have_content "Sit"
|
||||||
|
click_button 'Sit', match: :first
|
||||||
|
#TODO: Fix race condition. Trigger game react component reload when player joins a table
|
||||||
|
sleep 4
|
||||||
|
expect(page).to have_content @user.email
|
||||||
|
expect(page.text.scan(@user.email).count).to eq 2
|
||||||
|
end
|
||||||
|
|
||||||
|
scenario 'user can leave the current game', js: true do
|
||||||
|
expect(page).to have_content "Sit"
|
||||||
|
click_button 'Sit', match: :first
|
||||||
|
#TODO: Fix race condition
|
||||||
|
sleep 4
|
||||||
|
expect(page.text.scan(@user.email).count).to eq 2
|
||||||
|
click_button 'Stand', match: :first
|
||||||
|
expect(page).to have_content "Sit"
|
||||||
|
#TODO: Fix race condition
|
||||||
|
sleep 4
|
||||||
|
expect(page.text.scan(@user.email).count).to eq 0
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
60
spec/features/tables/table_show_spec.rb
Normal file
60
spec/features/tables/table_show_spec.rb
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
# Feature: Table show
|
||||||
|
# As a visitor
|
||||||
|
# I want to view a table
|
||||||
|
# So I can sit and play a game
|
||||||
|
feature 'Table show', :devise do
|
||||||
|
context "As a visitor" do
|
||||||
|
before(:each) do
|
||||||
|
@table = FactoryGirl.create :table
|
||||||
|
visit tables_path
|
||||||
|
click_link @table.title
|
||||||
|
end
|
||||||
|
# Scenario: Visitor can view a table
|
||||||
|
# Given I am not signed in
|
||||||
|
# When I visit a table
|
||||||
|
# Then I see the table attributes
|
||||||
|
scenario 'visitor can see the table', js: true do
|
||||||
|
expect(page).to have_selector "#table-#{@table.id} > h1", @table.title
|
||||||
|
end
|
||||||
|
|
||||||
|
scenario 'visitor can see the seats', js: true do
|
||||||
|
#TODO: Race condition exists without have_content
|
||||||
|
expect(page).to have_content "Sit"
|
||||||
|
@seat_count = page.find_all(".seat").length
|
||||||
|
expect(@seat_count).to eq @table.seats.count
|
||||||
|
end
|
||||||
|
|
||||||
|
scenario 'visitor can see the current game', js: true do
|
||||||
|
#TODO: Write a better expectation
|
||||||
|
expect(page).to have_content "Hand to beat"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "As a user" do
|
||||||
|
before(:each) do
|
||||||
|
@table = FactoryGirl.create :table
|
||||||
|
@user = FactoryGirl.create :user
|
||||||
|
signin(@user.email, @user.password)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Scenario: User can view a table
|
||||||
|
# Given I am signed in
|
||||||
|
# When I click a table
|
||||||
|
# Then I see the table attributes
|
||||||
|
scenario 'user can see the table', js: true do
|
||||||
|
visit tables_path
|
||||||
|
click_link @table.title
|
||||||
|
expect(page).to have_content "Sign out"
|
||||||
|
expect(page).to have_selector "#table-#{@table.id} > h1", @table.title
|
||||||
|
expect(current_path).to eq table_path(@table)
|
||||||
|
end
|
||||||
|
|
||||||
|
scenario 'user can see the current game', js: true do
|
||||||
|
#TODO: Fix race condition
|
||||||
|
visit table_path @table
|
||||||
|
#TODO: Write a better expectation
|
||||||
|
expect(page).to have_content "Hand to beat"
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
@ -8,7 +8,7 @@ feature 'Sign in', :devise do
|
|||||||
# When I sign in with valid credentials
|
# When I sign in with valid credentials
|
||||||
# Then I see an invalid credentials message
|
# Then I see an invalid credentials message
|
||||||
scenario 'user cannot sign in if not registered' do
|
scenario 'user cannot sign in if not registered' do
|
||||||
signin('test@example.com', 'please123')
|
signin('test@example.com', 'password')
|
||||||
expect(page).to have_content
|
expect(page).to have_content
|
||||||
I18n.t 'devise.failure.not_found_in_database', authentication_keys: 'email'
|
I18n.t 'devise.failure.not_found_in_database', authentication_keys: 'email'
|
||||||
end
|
end
|
||||||
|
|||||||
@ -20,4 +20,9 @@ feature 'Join game', :devise do
|
|||||||
@playerComponent = page.find("#player-1")
|
@playerComponent = page.find("#player-1")
|
||||||
expect(@playerComponent.text).to have_content("Guest#{@player.soft_token[0..5]}")
|
expect(@playerComponent.text).to have_content("Guest#{@player.soft_token[0..5]}")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
scenario 'visitor can join a game in progress' do
|
||||||
|
pending "To Be Implemented"
|
||||||
|
expect(page).to have_content "Waiting for next game."
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@ -9,13 +9,31 @@ RSpec.describe Seat, type: :model do
|
|||||||
|
|
||||||
it { should respond_to :table }
|
it { should respond_to :table }
|
||||||
it { should respond_to :user }
|
it { should respond_to :user }
|
||||||
|
it { should respond_to :user_id }
|
||||||
|
it { should respond_to :user_soft_token }
|
||||||
|
|
||||||
it '#table returns a Table' do
|
it '#table returns a Table' do
|
||||||
expect(@seat.table.class).to match Table
|
expect(@seat.table.class).to match Table
|
||||||
end
|
end
|
||||||
|
|
||||||
it '#user returns a User' do
|
it '#user returns a User' do
|
||||||
|
@seat = FactoryGirl.create(:seat, :occupied)
|
||||||
expect(@seat.user.class).to match User
|
expect(@seat.user.class).to match User
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it '#user_id returns a Fixnum' do
|
||||||
|
@seat = FactoryGirl.create(:seat, :occupied)
|
||||||
|
expect(@seat.user_id.class).to match Fixnum
|
||||||
|
end
|
||||||
|
|
||||||
|
it '#user_soft_token returns a String' do
|
||||||
|
@seat = FactoryGirl.create(:seat, :occupied)
|
||||||
|
expect(@seat.user_soft_token.class).to match String
|
||||||
|
end
|
||||||
|
|
||||||
|
it "#occupied? returns a Boolean" do
|
||||||
|
expect(@seat.occupied?).to eq false
|
||||||
|
@seat.user_id = 1
|
||||||
|
expect(@seat.occupied?).to eq true
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@ -33,4 +33,8 @@ RSpec.describe Table, type: :model do
|
|||||||
expect(@table.current_game.class).to match Game
|
expect(@table.current_game.class).to match Game
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "#seats returns 4 seats by default" do
|
||||||
|
expect(@table.seats.count).to eq 4
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@ -7,10 +7,10 @@ module Features
|
|||||||
user2 = FactoryGirl.create :user
|
user2 = FactoryGirl.create :user
|
||||||
user3 = FactoryGirl.create :user
|
user3 = FactoryGirl.create :user
|
||||||
user4 = FactoryGirl.create :user
|
user4 = FactoryGirl.create :user
|
||||||
game.add_player_from_user user1
|
game.seats[0].sit user1
|
||||||
game.add_player_from_user user2
|
game.seats[1].sit user2
|
||||||
game.add_player_from_user user3
|
game.seats[2].sit user3
|
||||||
game.add_player_from_user user4
|
game.seats[3].sit user4
|
||||||
game.start
|
game.start
|
||||||
return game
|
return game
|
||||||
end
|
end
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user