├── .gitignore
├── Gemfile
├── Gemfile.lock
├── README.md
├── Rakefile
├── app
├── assets
│ ├── config
│ │ └── manifest.js
│ ├── images
│ │ ├── .keep
│ │ ├── Aarron.jpeg
│ │ ├── Ben_Blue_.jpeg
│ │ ├── Benjamin_Berman_.jpeg
│ │ ├── Chao_.jpeg
│ │ ├── Chris_Lee.jpeg
│ │ ├── Chris_Lew_.jpeg
│ │ ├── Collin_.jpeg
│ │ ├── Corey_.jpeg
│ │ ├── Daniel_Nam.jpeg
│ │ ├── David_Veytsman_.jpeg
│ │ ├── David_Webster.jpeg
│ │ ├── Drew.jpeg
│ │ ├── Elliott_.jpeg
│ │ ├── Emily_.jpeg
│ │ ├── Ethan_.jpeg
│ │ ├── George.jpeg
│ │ ├── Glenn_.jpeg
│ │ ├── Hanhee.jpeg
│ │ ├── Isaac.jpeg
│ │ ├── Kelby_.jpeg
│ │ ├── Kennan_Zhong_.jpeg
│ │ ├── Kevin_Coppa.jpeg
│ │ ├── Kevin_Migueis_.jpeg
│ │ ├── Kristina_.jpeg
│ │ ├── Matthew_Liu_.jpeg
│ │ ├── Matthew_Ruddy_.jpeg
│ │ ├── Max.jpeg
│ │ ├── Mengling_Ren_.jpeg
│ │ ├── Michael_Cohen_.jpeg
│ │ ├── Neil_Gewirtz.jpeg
│ │ ├── Noe.jpeg
│ │ ├── Oguzhen_.jpeg
│ │ ├── Omar.jpeg
│ │ ├── Ommi.jpeg
│ │ ├── Patrick_.jpeg
│ │ ├── Patrick_Fulghum_.jpeg
│ │ ├── Raymond_.jpeg
│ │ ├── Rick.jpeg
│ │ ├── Steven_Ossorio_.jpeg
│ │ ├── Thomas_H.jpeg
│ │ ├── Thuy_.jpeg
│ │ ├── Valery_.jpeg
│ │ ├── Victor.jpeg
│ │ ├── accounting.jpeg
│ │ ├── background.jpg
│ │ ├── biology.jpg
│ │ ├── chemistry.jpeg
│ │ ├── coding.jpg
│ │ ├── default.jpeg
│ │ ├── favicon.ico
│ │ ├── history.jpg
│ │ ├── howitworks1.svg
│ │ ├── howitworks2.svg
│ │ ├── howitworks3.svg
│ │ ├── loginpage.jpg
│ │ ├── logo.png
│ │ ├── physics.jpeg
│ │ ├── pledge.svg
│ │ ├── socicon.eot
│ │ ├── socicon.svg
│ │ ├── socicon.ttf
│ │ ├── socicon.woff
│ │ ├── taskrabbitbg.jpg
│ │ ├── test-prep.jpeg
│ │ ├── trusticon.svg
│ │ └── workspace.jpg
│ ├── javascripts
│ │ ├── application.js
│ │ ├── cable.js
│ │ └── channels
│ │ │ └── .keep
│ └── stylesheets
│ │ ├── account.scss
│ │ ├── application.css
│ │ ├── booking_item.scss
│ │ ├── completebooking.scss
│ │ ├── confirm.scss
│ │ ├── dashboard.scss
│ │ ├── fbgooglelogin.scss
│ │ ├── form.scss
│ │ ├── google.scss
│ │ ├── homepage.scss
│ │ ├── login.scss
│ │ ├── modal.scss
│ │ ├── searchbar.scss
│ │ ├── show.scss
│ │ ├── signup.scss
│ │ ├── socialicons.scss
│ │ └── taskerform.scss
├── channels
│ └── application_cable
│ │ ├── channel.rb
│ │ └── connection.rb
├── controllers
│ ├── api
│ │ ├── hired_tutors_controller.rb
│ │ ├── reviews_controller.rb
│ │ ├── sessions_controller.rb
│ │ ├── subjects_controller.rb
│ │ ├── tutors_for_hires_controller.rb
│ │ └── users_controller.rb
│ ├── application_controller.rb
│ ├── concerns
│ │ └── .keep
│ └── static_pages_controller.rb
├── helpers
│ └── application_helper.rb
├── jobs
│ └── application_job.rb
├── mailers
│ └── application_mailer.rb
├── models
│ ├── application_record.rb
│ ├── available_time.rb
│ ├── concerns
│ │ └── .keep
│ ├── hired_tutor.rb
│ ├── review.rb
│ ├── subject.rb
│ ├── time_of_day.rb
│ ├── tutors_for_hire.rb
│ └── user.rb
└── views
│ ├── api
│ ├── hired_tutors
│ │ └── index.json.jbuilder
│ ├── tutors_for_hires
│ │ └── index.json.jbuilder
│ └── users
│ │ ├── _user.json.jbuilder
│ │ └── show.json.jbuilder
│ ├── layouts
│ ├── application.html.erb
│ ├── mailer.html.erb
│ └── mailer.text.erb
│ └── static_pages
│ └── root.html.erb
├── bin
├── bundle
├── rails
├── rake
├── setup
├── spring
├── update
└── yarn
├── config.ru
├── config
├── application.rb
├── boot.rb
├── cable.yml
├── database.yml
├── environment.rb
├── environments
│ ├── development.rb
│ ├── production.rb
│ └── test.rb
├── initializers
│ ├── application_controller_renderer.rb
│ ├── assets.rb
│ ├── backtrace_silencers.rb
│ ├── cookies_serializer.rb
│ ├── filter_parameter_logging.rb
│ ├── inflections.rb
│ ├── mime_types.rb
│ └── wrap_parameters.rb
├── locales
│ └── en.yml
├── puma.rb
├── routes.rb
├── secrets.yml
└── spring.rb
├── db
├── migrate
│ ├── 20171024150133_create_users.rb
│ ├── 20171024150536_deleteusers.rb
│ ├── 20171024150642_addnewusertable.rb
│ ├── 20171024151058_deletenewusers.rb
│ ├── 20171024152237_newusers.rb
│ ├── 20171024170632_changenames.rb
│ ├── 20171024212555_create_subjects.rb
│ ├── 20171024212841_create_tutors_for_hires.rb
│ ├── 20171024214306_create_available_times.rb
│ ├── 20171024214544_create_hired_tutors.rb
│ ├── 20171024214708_create_reviews.rb
│ ├── 20171024234541_deletethingsfromtutorstable.rb
│ ├── 20171024234943_updatebooleans.rb
│ ├── 20171027131139_add_attachment_image_to_users.rb
│ ├── 20171027193700_create_time_of_days.rb
│ ├── 20171029231855_changehiredtutors.rb
│ ├── 20171029235356_edit_hiredtutor.rb
│ ├── 20171029235954_add_default_completed.rb
│ └── 20171101134706_addsubjecttoreview.rb
├── schema.rb
└── seeds.rb
├── frontend
├── actions
│ ├── session_actions.js
│ ├── tutor_actions.js
│ └── ui_actions.js
├── components
│ ├── App.jsx
│ ├── account
│ │ ├── account.jsx
│ │ ├── account_container.js
│ │ ├── account_edit_form.jsx
│ │ ├── account_edit_form_container.js
│ │ ├── account_edit_form_container.jsx
│ │ ├── account_info.jsx
│ │ └── account_info_container.js
│ ├── becometasker
│ │ ├── tasker_form.jsx
│ │ └── tasker_form_container.js
│ ├── dashboard
│ │ ├── booking_item.jsx
│ │ ├── complete_booking.jsx
│ │ ├── complete_booking_container.js
│ │ ├── dashboard.jsx
│ │ ├── dashboard_container.js
│ │ └── how_to_get_started.jsx
│ ├── greeting
│ │ ├── greeting.jsx
│ │ └── greeting_container.js
│ ├── homepage
│ │ ├── header.jsx
│ │ ├── homepage.jsx
│ │ ├── homepage_container.js
│ │ ├── how_it_works.jsx
│ │ └── results.jsx
│ ├── login_form
│ │ ├── login_form.jsx
│ │ └── login_form_container.js
│ ├── root.jsx
│ ├── shared
│ │ ├── error_handler.jsx
│ │ ├── footer.jsx
│ │ ├── header.jsx
│ │ └── trust_banner.jsx
│ ├── signup_form
│ │ ├── signup_form.jsx
│ │ └── signup_form_container.js
│ └── tutor_form
│ │ ├── date_box_item.jsx
│ │ ├── google
│ │ └── google_autocomplete.js
│ │ ├── modals
│ │ ├── login_modal.jsx
│ │ ├── login_modal_container.js
│ │ └── signup_modal.jsx
│ │ ├── sorting_container.jsx
│ │ ├── tutor_confirm.jsx
│ │ ├── tutor_confirm_container.js
│ │ ├── tutor_form.jsx
│ │ ├── tutor_form_container.js
│ │ ├── tutor_list_item.jsx
│ │ ├── tutor_show.jsx
│ │ └── tutor_show_container.js
├── reducers
│ ├── errors_reducer.js
│ ├── root_reducer.js
│ ├── session_errors_reducer.js
│ ├── session_reducer.js
│ ├── tutors_reducer.js
│ └── ui_reducer.js
├── store
│ └── store.js
├── taskable.jsx
└── util
│ ├── auth_route.jsx
│ ├── session_api_util.js
│ └── tutor_api_util.js
├── lib
├── assets
│ └── .keep
└── tasks
│ └── .keep
├── package.json
├── public
├── 404.html
├── 422.html
├── 500.html
├── apple-touch-icon-precomposed.png
├── apple-touch-icon.png
├── favicon.ico
└── robots.txt
├── test
├── application_system_test_case.rb
├── controllers
│ └── .keep
├── fixtures
│ ├── .keep
│ ├── available_times.yml
│ ├── files
│ │ └── .keep
│ ├── hired_tutors.yml
│ ├── reviews.yml
│ ├── subjects.yml
│ ├── time_of_days.yml
│ ├── tutors_for_hires.yml
│ └── users.yml
├── helpers
│ └── .keep
├── integration
│ └── .keep
├── mailers
│ └── .keep
├── models
│ ├── .keep
│ ├── available_time_test.rb
│ ├── hired_tutor_test.rb
│ ├── review_test.rb
│ ├── subject_test.rb
│ ├── time_of_day_test.rb
│ ├── tutors_for_hire_test.rb
│ └── user_test.rb
├── system
│ └── .keep
└── test_helper.rb
├── vendor
└── .keep
├── webpack.config.js
└── wireframe
├── homepage:signup.png
├── login:taskform.png
└── taskshow.png
/.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 |
7 | # Ignore bundler config.
8 | /.bundle
9 |
10 | # Ignore all logfiles and tempfiles.
11 | /log/*
12 | /tmp/*
13 | !/log/.keep
14 | !/tmp/.keep
15 |
16 | /node_modules
17 | /yarn-error.log
18 |
19 | .byebug_history
20 | .bundle.js
21 | .bundle.map.js
22 | .byebug_history
23 | .DS_Store
24 | npm-debug.log
25 |
26 | # Ignore application configuration
27 | /config/application.yml
28 |
--------------------------------------------------------------------------------
/Gemfile:
--------------------------------------------------------------------------------
1 | source 'https://rubygems.org'
2 |
3 | git_source(:github) do |repo_name|
4 | repo_name = "#{repo_name}/#{repo_name}" unless repo_name.include?("/")
5 | "https://github.com/#{repo_name}.git"
6 | end
7 | gem 'paperclip', "~> 5.0.0"
8 | gem 'figaro'
9 | gem 'rails_12factor'
10 | gem 'aws-sdk', '< 3.0'
11 | gem 'annotate'
12 | # Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
13 | gem 'rails', '~> 5.1.4'
14 | # Use postgresql as the database for Active Record
15 | gem 'pg', '~> 0.18'
16 | # Use Puma as the app server
17 | gem 'puma', '~> 3.7'
18 | # Use SCSS for stylesheets
19 | gem 'sass-rails', '~> 5.0'
20 | # Use Uglifier as compressor for JavaScript assets
21 | gem 'uglifier', '>= 1.3.0'
22 | # See https://github.com/rails/execjs#readme for more supported runtimes
23 | # gem 'therubyracer', platforms: :ruby
24 |
25 | # Use CoffeeScript for .coffee assets and views
26 | gem 'coffee-rails', '~> 4.2'
27 | # Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder
28 | gem 'jbuilder', '~> 2.5'
29 | # Use Redis adapter to run Action Cable in production
30 | # gem 'redis', '~> 3.0'
31 | # Use ActiveModel has_secure_password
32 | gem 'bcrypt', '~> 3.1.7'
33 | gem 'jquery-rails'
34 |
35 | # Use Capistrano for deployment
36 | # gem 'capistrano-rails', group: :development
37 |
38 | group :development, :test do
39 | # Call 'byebug' anywhere in the code to stop execution and get a debugger console
40 | gem 'byebug', platforms: [:mri, :mingw, :x64_mingw]
41 | # Adds support for Capybara system testing and selenium driver
42 | gem 'capybara', '~> 2.13'
43 | gem 'selenium-webdriver'
44 | end
45 |
46 | group :development do
47 | # Access an IRB console on exception pages or by using <%= console %> anywhere in the code.
48 | gem 'web-console', '>= 3.3.0'
49 | gem 'listen', '>= 3.0.5', '< 3.2'
50 | # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring
51 | gem 'spring'
52 | gem 'spring-watcher-listen', '~> 2.0.0'
53 | end
54 |
55 | # Windows does not include zoneinfo files, so bundle the tzinfo-data gem
56 | gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]
57 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Taskable
2 | ==========
3 |
4 | 
5 |
6 | This is a Ruby on Rails application with a React-redux front-end inspired by the website TaskRabbit. It has the essential functionality of the TaskRabbit application but instead of hiring taskers for manual labor, Taskable allows hiring of tutors for educational help.
7 |
8 | ---
9 |
10 | ## Demo
11 | Here is the working live demo : https://taskable.me/
12 |
13 |
14 | 
15 |
16 | ## Features
17 | - User authentication with additional social log in buttons (Facebook/Google)
18 | - Searching for address using Google Places Api autocomplete
19 | - Front-end sorting of search results using date, time, and other parameters
20 | - Ability to browse website while not signed in
21 | - Prompts a sign-in if attempting to book a tutor
22 | - Select a tutor, input fake payment information
23 | - Complete bookings by adding a review
24 | - Update user information with a profile picture
25 | - many more awesome features to come...
26 |
27 |
28 | ## Landing Page
29 |
30 | 
31 |
32 | ## Result Filtering and Sorting
33 |
34 | 
35 |
36 | A sorted by field, a date field, and time selection dropdown were created to help filter and sort the results of your search.
37 | Implementing all three parameters was tricky, making sure each change changed the React state of the page accordingly. A change in the state triggers a re-filter of the list of available tutors and re-renders the updated, sorted list.
38 |
39 | #### Creating an array of date selection boxes
40 |
41 | ```
42 | dateArrays(num) {
43 | let result = [];
44 | let x = new Date;
45 | for (var i = 0; i < num; i++) {
46 | result.push({
47 | date: (x.toDateString().slice(4,10).trim()),
48 | day: x.getDay(),
49 | day_string: x.toDateString().slice(0,3)
50 | });
51 | x.setDate(x.getDate() + 1);
52 | }
53 | result[0].day_string = 'Today';
54 | return result;
55 | }
56 | ```
57 |
58 | ## Prompt login or signup upon booking
59 |
60 | If user attempts to make a booking but is not signed in, a modal comes up to prompt user to sign up or log in.
61 |
62 | After logging in or signing up, they are subsequently logged in and able to make a booking. Users can switch between the signup and login modal.
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 | ## Built with
73 | - [Ruby on Rails](http://rubyonrails.org/) - A server-side web application framework written in Ruby, a MVC framework.
74 | - [React](https://reactjs.org/) - React is a JS library to build an interactive, seamless UI
75 | - [Redux](https://redux.js.org/) - Predictable state container for JS apps
76 | - [React-Redux](https://github.com/reactjs/react-redux) - Binds React state with Redux store
77 | - [Google Maps Places Api](https://developers.google.com/places/web-service/) - Gets data from same database used by Google Maps.
78 | - [Facebook Login Api](https://developers.facebook.com/docs/facebook-login/) - Facebook Login is a secure, fast and convenient way for people to log into your app or website.
79 | - [Google Signin](https://developers.google.com/identity/) - Google Sign-In is a secure authentication system that reduces the burden of login for your users, by enabling them to sign in with their Google account.
80 |
81 | ## To-do
82 | - Implement reviews for each tutor. When browsing available tutors, users should be able to click on an individual user and view all of their previous reviews and a rating based on all of those reviews.
83 | - Add location functionality - check whether or not user inputted address is within range of any tutors.
84 | - Add a form for users to become a tutor
85 |
--------------------------------------------------------------------------------
/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/config/manifest.js:
--------------------------------------------------------------------------------
1 | //= link_tree ../images
2 | //= link_directory ../javascripts .js
3 | //= link_directory ../stylesheets .css
4 |
--------------------------------------------------------------------------------
/app/assets/images/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/victorwu3/Taskable/06e826e3edd0982683390a5bf3ce7f36bc7d8a9f/app/assets/images/.keep
--------------------------------------------------------------------------------
/app/assets/images/Aarron.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/victorwu3/Taskable/06e826e3edd0982683390a5bf3ce7f36bc7d8a9f/app/assets/images/Aarron.jpeg
--------------------------------------------------------------------------------
/app/assets/images/Ben_Blue_.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/victorwu3/Taskable/06e826e3edd0982683390a5bf3ce7f36bc7d8a9f/app/assets/images/Ben_Blue_.jpeg
--------------------------------------------------------------------------------
/app/assets/images/Benjamin_Berman_.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/victorwu3/Taskable/06e826e3edd0982683390a5bf3ce7f36bc7d8a9f/app/assets/images/Benjamin_Berman_.jpeg
--------------------------------------------------------------------------------
/app/assets/images/Chao_.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/victorwu3/Taskable/06e826e3edd0982683390a5bf3ce7f36bc7d8a9f/app/assets/images/Chao_.jpeg
--------------------------------------------------------------------------------
/app/assets/images/Chris_Lee.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/victorwu3/Taskable/06e826e3edd0982683390a5bf3ce7f36bc7d8a9f/app/assets/images/Chris_Lee.jpeg
--------------------------------------------------------------------------------
/app/assets/images/Chris_Lew_.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/victorwu3/Taskable/06e826e3edd0982683390a5bf3ce7f36bc7d8a9f/app/assets/images/Chris_Lew_.jpeg
--------------------------------------------------------------------------------
/app/assets/images/Collin_.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/victorwu3/Taskable/06e826e3edd0982683390a5bf3ce7f36bc7d8a9f/app/assets/images/Collin_.jpeg
--------------------------------------------------------------------------------
/app/assets/images/Corey_.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/victorwu3/Taskable/06e826e3edd0982683390a5bf3ce7f36bc7d8a9f/app/assets/images/Corey_.jpeg
--------------------------------------------------------------------------------
/app/assets/images/Daniel_Nam.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/victorwu3/Taskable/06e826e3edd0982683390a5bf3ce7f36bc7d8a9f/app/assets/images/Daniel_Nam.jpeg
--------------------------------------------------------------------------------
/app/assets/images/David_Veytsman_.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/victorwu3/Taskable/06e826e3edd0982683390a5bf3ce7f36bc7d8a9f/app/assets/images/David_Veytsman_.jpeg
--------------------------------------------------------------------------------
/app/assets/images/David_Webster.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/victorwu3/Taskable/06e826e3edd0982683390a5bf3ce7f36bc7d8a9f/app/assets/images/David_Webster.jpeg
--------------------------------------------------------------------------------
/app/assets/images/Drew.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/victorwu3/Taskable/06e826e3edd0982683390a5bf3ce7f36bc7d8a9f/app/assets/images/Drew.jpeg
--------------------------------------------------------------------------------
/app/assets/images/Elliott_.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/victorwu3/Taskable/06e826e3edd0982683390a5bf3ce7f36bc7d8a9f/app/assets/images/Elliott_.jpeg
--------------------------------------------------------------------------------
/app/assets/images/Emily_.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/victorwu3/Taskable/06e826e3edd0982683390a5bf3ce7f36bc7d8a9f/app/assets/images/Emily_.jpeg
--------------------------------------------------------------------------------
/app/assets/images/Ethan_.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/victorwu3/Taskable/06e826e3edd0982683390a5bf3ce7f36bc7d8a9f/app/assets/images/Ethan_.jpeg
--------------------------------------------------------------------------------
/app/assets/images/George.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/victorwu3/Taskable/06e826e3edd0982683390a5bf3ce7f36bc7d8a9f/app/assets/images/George.jpeg
--------------------------------------------------------------------------------
/app/assets/images/Glenn_.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/victorwu3/Taskable/06e826e3edd0982683390a5bf3ce7f36bc7d8a9f/app/assets/images/Glenn_.jpeg
--------------------------------------------------------------------------------
/app/assets/images/Hanhee.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/victorwu3/Taskable/06e826e3edd0982683390a5bf3ce7f36bc7d8a9f/app/assets/images/Hanhee.jpeg
--------------------------------------------------------------------------------
/app/assets/images/Isaac.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/victorwu3/Taskable/06e826e3edd0982683390a5bf3ce7f36bc7d8a9f/app/assets/images/Isaac.jpeg
--------------------------------------------------------------------------------
/app/assets/images/Kelby_.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/victorwu3/Taskable/06e826e3edd0982683390a5bf3ce7f36bc7d8a9f/app/assets/images/Kelby_.jpeg
--------------------------------------------------------------------------------
/app/assets/images/Kennan_Zhong_.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/victorwu3/Taskable/06e826e3edd0982683390a5bf3ce7f36bc7d8a9f/app/assets/images/Kennan_Zhong_.jpeg
--------------------------------------------------------------------------------
/app/assets/images/Kevin_Coppa.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/victorwu3/Taskable/06e826e3edd0982683390a5bf3ce7f36bc7d8a9f/app/assets/images/Kevin_Coppa.jpeg
--------------------------------------------------------------------------------
/app/assets/images/Kevin_Migueis_.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/victorwu3/Taskable/06e826e3edd0982683390a5bf3ce7f36bc7d8a9f/app/assets/images/Kevin_Migueis_.jpeg
--------------------------------------------------------------------------------
/app/assets/images/Kristina_.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/victorwu3/Taskable/06e826e3edd0982683390a5bf3ce7f36bc7d8a9f/app/assets/images/Kristina_.jpeg
--------------------------------------------------------------------------------
/app/assets/images/Matthew_Liu_.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/victorwu3/Taskable/06e826e3edd0982683390a5bf3ce7f36bc7d8a9f/app/assets/images/Matthew_Liu_.jpeg
--------------------------------------------------------------------------------
/app/assets/images/Matthew_Ruddy_.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/victorwu3/Taskable/06e826e3edd0982683390a5bf3ce7f36bc7d8a9f/app/assets/images/Matthew_Ruddy_.jpeg
--------------------------------------------------------------------------------
/app/assets/images/Max.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/victorwu3/Taskable/06e826e3edd0982683390a5bf3ce7f36bc7d8a9f/app/assets/images/Max.jpeg
--------------------------------------------------------------------------------
/app/assets/images/Mengling_Ren_.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/victorwu3/Taskable/06e826e3edd0982683390a5bf3ce7f36bc7d8a9f/app/assets/images/Mengling_Ren_.jpeg
--------------------------------------------------------------------------------
/app/assets/images/Michael_Cohen_.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/victorwu3/Taskable/06e826e3edd0982683390a5bf3ce7f36bc7d8a9f/app/assets/images/Michael_Cohen_.jpeg
--------------------------------------------------------------------------------
/app/assets/images/Neil_Gewirtz.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/victorwu3/Taskable/06e826e3edd0982683390a5bf3ce7f36bc7d8a9f/app/assets/images/Neil_Gewirtz.jpeg
--------------------------------------------------------------------------------
/app/assets/images/Noe.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/victorwu3/Taskable/06e826e3edd0982683390a5bf3ce7f36bc7d8a9f/app/assets/images/Noe.jpeg
--------------------------------------------------------------------------------
/app/assets/images/Oguzhen_.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/victorwu3/Taskable/06e826e3edd0982683390a5bf3ce7f36bc7d8a9f/app/assets/images/Oguzhen_.jpeg
--------------------------------------------------------------------------------
/app/assets/images/Omar.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/victorwu3/Taskable/06e826e3edd0982683390a5bf3ce7f36bc7d8a9f/app/assets/images/Omar.jpeg
--------------------------------------------------------------------------------
/app/assets/images/Ommi.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/victorwu3/Taskable/06e826e3edd0982683390a5bf3ce7f36bc7d8a9f/app/assets/images/Ommi.jpeg
--------------------------------------------------------------------------------
/app/assets/images/Patrick_.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/victorwu3/Taskable/06e826e3edd0982683390a5bf3ce7f36bc7d8a9f/app/assets/images/Patrick_.jpeg
--------------------------------------------------------------------------------
/app/assets/images/Patrick_Fulghum_.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/victorwu3/Taskable/06e826e3edd0982683390a5bf3ce7f36bc7d8a9f/app/assets/images/Patrick_Fulghum_.jpeg
--------------------------------------------------------------------------------
/app/assets/images/Raymond_.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/victorwu3/Taskable/06e826e3edd0982683390a5bf3ce7f36bc7d8a9f/app/assets/images/Raymond_.jpeg
--------------------------------------------------------------------------------
/app/assets/images/Rick.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/victorwu3/Taskable/06e826e3edd0982683390a5bf3ce7f36bc7d8a9f/app/assets/images/Rick.jpeg
--------------------------------------------------------------------------------
/app/assets/images/Steven_Ossorio_.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/victorwu3/Taskable/06e826e3edd0982683390a5bf3ce7f36bc7d8a9f/app/assets/images/Steven_Ossorio_.jpeg
--------------------------------------------------------------------------------
/app/assets/images/Thomas_H.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/victorwu3/Taskable/06e826e3edd0982683390a5bf3ce7f36bc7d8a9f/app/assets/images/Thomas_H.jpeg
--------------------------------------------------------------------------------
/app/assets/images/Thuy_.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/victorwu3/Taskable/06e826e3edd0982683390a5bf3ce7f36bc7d8a9f/app/assets/images/Thuy_.jpeg
--------------------------------------------------------------------------------
/app/assets/images/Valery_.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/victorwu3/Taskable/06e826e3edd0982683390a5bf3ce7f36bc7d8a9f/app/assets/images/Valery_.jpeg
--------------------------------------------------------------------------------
/app/assets/images/Victor.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/victorwu3/Taskable/06e826e3edd0982683390a5bf3ce7f36bc7d8a9f/app/assets/images/Victor.jpeg
--------------------------------------------------------------------------------
/app/assets/images/accounting.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/victorwu3/Taskable/06e826e3edd0982683390a5bf3ce7f36bc7d8a9f/app/assets/images/accounting.jpeg
--------------------------------------------------------------------------------
/app/assets/images/background.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/victorwu3/Taskable/06e826e3edd0982683390a5bf3ce7f36bc7d8a9f/app/assets/images/background.jpg
--------------------------------------------------------------------------------
/app/assets/images/biology.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/victorwu3/Taskable/06e826e3edd0982683390a5bf3ce7f36bc7d8a9f/app/assets/images/biology.jpg
--------------------------------------------------------------------------------
/app/assets/images/chemistry.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/victorwu3/Taskable/06e826e3edd0982683390a5bf3ce7f36bc7d8a9f/app/assets/images/chemistry.jpeg
--------------------------------------------------------------------------------
/app/assets/images/coding.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/victorwu3/Taskable/06e826e3edd0982683390a5bf3ce7f36bc7d8a9f/app/assets/images/coding.jpg
--------------------------------------------------------------------------------
/app/assets/images/default.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/victorwu3/Taskable/06e826e3edd0982683390a5bf3ce7f36bc7d8a9f/app/assets/images/default.jpeg
--------------------------------------------------------------------------------
/app/assets/images/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/victorwu3/Taskable/06e826e3edd0982683390a5bf3ce7f36bc7d8a9f/app/assets/images/favicon.ico
--------------------------------------------------------------------------------
/app/assets/images/history.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/victorwu3/Taskable/06e826e3edd0982683390a5bf3ce7f36bc7d8a9f/app/assets/images/history.jpg
--------------------------------------------------------------------------------
/app/assets/images/howitworks3.svg:
--------------------------------------------------------------------------------
1 | Asset 18 heart heart heart heart heart heart
--------------------------------------------------------------------------------
/app/assets/images/loginpage.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/victorwu3/Taskable/06e826e3edd0982683390a5bf3ce7f36bc7d8a9f/app/assets/images/loginpage.jpg
--------------------------------------------------------------------------------
/app/assets/images/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/victorwu3/Taskable/06e826e3edd0982683390a5bf3ce7f36bc7d8a9f/app/assets/images/logo.png
--------------------------------------------------------------------------------
/app/assets/images/physics.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/victorwu3/Taskable/06e826e3edd0982683390a5bf3ce7f36bc7d8a9f/app/assets/images/physics.jpeg
--------------------------------------------------------------------------------
/app/assets/images/pledge.svg:
--------------------------------------------------------------------------------
1 | Asset 10
--------------------------------------------------------------------------------
/app/assets/images/socicon.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/victorwu3/Taskable/06e826e3edd0982683390a5bf3ce7f36bc7d8a9f/app/assets/images/socicon.eot
--------------------------------------------------------------------------------
/app/assets/images/socicon.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/victorwu3/Taskable/06e826e3edd0982683390a5bf3ce7f36bc7d8a9f/app/assets/images/socicon.ttf
--------------------------------------------------------------------------------
/app/assets/images/socicon.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/victorwu3/Taskable/06e826e3edd0982683390a5bf3ce7f36bc7d8a9f/app/assets/images/socicon.woff
--------------------------------------------------------------------------------
/app/assets/images/taskrabbitbg.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/victorwu3/Taskable/06e826e3edd0982683390a5bf3ce7f36bc7d8a9f/app/assets/images/taskrabbitbg.jpg
--------------------------------------------------------------------------------
/app/assets/images/test-prep.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/victorwu3/Taskable/06e826e3edd0982683390a5bf3ce7f36bc7d8a9f/app/assets/images/test-prep.jpeg
--------------------------------------------------------------------------------
/app/assets/images/workspace.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/victorwu3/Taskable/06e826e3edd0982683390a5bf3ce7f36bc7d8a9f/app/assets/images/workspace.jpg
--------------------------------------------------------------------------------
/app/assets/javascripts/application.js:
--------------------------------------------------------------------------------
1 | // This is a manifest file that'll be compiled into application.js, which will include all the files
2 | // listed below.
3 | //
4 | // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, or any plugin's
5 | // vendor/assets/javascripts directory can be referenced here using a relative path.
6 | //
7 | // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
8 | // compiled file. JavaScript code in this file should be added after the last require_* statement.
9 | //
10 | // Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
11 | // about supported directives.
12 | //
13 | //= require rails-ujs
14 | //= require_tree .
15 | //= require jquery
16 | //= require jquery_ujs
17 |
--------------------------------------------------------------------------------
/app/assets/javascripts/cable.js:
--------------------------------------------------------------------------------
1 | // Action Cable provides the framework to deal with WebSockets in Rails.
2 | // You can generate new channels where WebSocket features live using the `rails generate channel` command.
3 | //
4 | //= require action_cable
5 | //= require_self
6 | //= require_tree ./channels
7 |
8 | (function() {
9 | this.App || (this.App = {});
10 |
11 | App.cable = ActionCable.createConsumer();
12 |
13 | }).call(this);
14 |
--------------------------------------------------------------------------------
/app/assets/javascripts/channels/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/victorwu3/Taskable/06e826e3edd0982683390a5bf3ce7f36bc7d8a9f/app/assets/javascripts/channels/.keep
--------------------------------------------------------------------------------
/app/assets/stylesheets/account.scss:
--------------------------------------------------------------------------------
1 | .account-container {
2 | width: 960px;
3 | margin: 0 auto;
4 | }
5 |
6 | .account-box {
7 | border: 1px solid #dce0e6;
8 | background-color: white;
9 | border-radius: 4px;
10 | }
11 |
12 | .account-portal {
13 | display: flex;
14 |
15 | }
16 |
17 | .account-info {
18 | width: 70%;
19 | padding: 1em;
20 | }
21 |
22 | .account-info-title {
23 | font-size: 1.75rem;
24 | position: absolute;
25 | top: -18px;
26 | }
27 |
28 | .account-panel {
29 | width: 25%;
30 | float: left;
31 | border-right: 1px solid #dce0e6;
32 | }
33 |
34 | .account-info-title-container {
35 | position: relative;
36 | }
37 | .account-info-row {
38 | display: flex;
39 | justify-content: space-between;
40 | align-items: baseline;
41 | margin-bottom: 1rem;
42 | border-bottom: 1px solid #dce0e6;
43 | padding-bottom: 1em;
44 | }
45 |
46 | .account-info-container {
47 | display: flex;
48 | }
49 |
50 | .account-infos-container {
51 | display: flex;
52 | flex-direction: column;
53 | }
54 |
55 | .account-list {
56 | list-style: none;
57 | margin-top: 2rem;
58 | }
59 |
60 | .account-list li {
61 | margin-bottom: 5px;
62 | font-size: 23px;
63 | font-weight: 300;
64 | display: flex;
65 | }
66 |
67 | .account-picture {
68 | height: 175px;
69 | width: 175px;
70 | border-radius: 50%;
71 | margin: 1rem 3rem;
72 | cursor: pointer;
73 | object-fit: cover;
74 | }
75 |
76 | .account-picture-container {
77 | display: flex;
78 | flex-direction: column;
79 | align-items: center;
80 | }
81 |
82 | .upload-photo-label {
83 | margin: .5rem 0;
84 | cursor: pointer;
85 | }
86 |
87 | .edit-input {
88 | margin-bottom: 7px;
89 | }
90 |
91 | .edit-form-btn {
92 | margin-left: 10px;
93 | font-size: 1.25rem;
94 | border: 1px solid #51af33;
95 | width: 100%;
96 | background: #51af33;
97 | border-radius: 4px;
98 | padding: 0.6em 4em 0.6em;
99 | text-decoration: none;
100 | color: white;
101 | margin-top: 8px;
102 | transition: background-color 0.5s ease;
103 | margin-bottom: 10px;
104 | }
105 |
106 | .edit-form-btn:hover {
107 | background-color: #438e29;
108 | color: white;
109 | transition: background-color 0.5s ease;
110 | cursor: pointer;
111 | }
112 |
113 | .upload-photo-label {
114 | height: 215px;
115 | width: 175px;
116 | position: absolute;
117 | z-index: 1;
118 | opacity: 0;
119 | }
120 |
121 | .side-nav {
122 | list-style: none;
123 | color: #51af33;
124 | padding-left: 0;
125 | margin: 0;
126 | }
127 |
128 | .side-nav-item {
129 | padding-left: 40px;
130 | padding: 18px 40px;
131 | cursor: pointer;
132 | }
133 |
134 | .side-nav-item:hover {
135 | border-left: 5px solid gray;
136 | }
137 |
138 | .side-nav-link {
139 | text-decoration: none;
140 | color: #51af33;
141 | }
142 |
143 | .side-nav-link:hover {
144 | color: #438e29;
145 |
146 | }
147 |
--------------------------------------------------------------------------------
/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 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/SCSS
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/booking_item.scss:
--------------------------------------------------------------------------------
1 | git.booking-item {
2 | min-width: 650px;
3 | border: 1px solid #dce0e6;
4 | border-radius: 4px;
5 | padding: 1em 1em;
6 | margin-bottom: 1rem;
7 | }
8 |
9 | .booking-result-figure {
10 | display: flex;
11 | flex-direction: row;
12 | justify-content: space-between;
13 | margin-bottom: 1rem;
14 | padding-bottom: 1rem;
15 | border-bottom: 1px solid #dce0e6;
16 | }
17 |
18 | .booking-picture {
19 | height: 35px;
20 | width: 35px;
21 | border-radius: 50%;
22 | object-fit: cover;
23 | }
24 |
25 | .booking-name {
26 | font-weight: 400;
27 | font-size: 1.75rem;
28 | }
29 |
30 |
31 | .booking-rate {
32 | float: right;
33 | }
34 |
35 | .booking-date-time-location {
36 | display: flex;
37 | font-weight: 200;
38 | justify-content: space-between;
39 | margin: 1.5rem 0;
40 | }
41 |
42 | .booking-date-container {
43 | display: flex;
44 | align-items: center;
45 | }
46 | .booking-date {
47 | margin-right: 1rem;
48 | padding-right: 1rem;
49 | border-right: 1px solid gray;
50 | font-weight: 400;
51 | }
52 |
53 | .booking-location-container {
54 | align-items: flex-end;
55 | display: flex;
56 | flex-direction: column;
57 | }
58 |
59 | .booking-content {
60 | display: flex;
61 | flex-direction: column;
62 | }
63 |
64 | .booking-item label {
65 | color: #67727e;
66 | font-weight: 200;
67 | font-size: .825rem;
68 | margin-bottom: .5rem;
69 | }
70 |
71 | .booking-complete-container {
72 | margin-top: 1rem;
73 | display: flex;
74 | flex-direction: column;
75 | align-items: center;
76 | }
77 |
78 | .complete-booking-button {
79 | font-size: 1.25rem;
80 | border: 1px solid #51af33;
81 | width: 50%;
82 | background: #51af33;
83 | border-radius: 4px;
84 | padding: 0.6em 4em 0.6em;
85 | text-decoration: none;
86 | color: white;
87 | margin-top: 8px;
88 | transition: background-color 0.5s ease;
89 | margin-bottom: 10px;
90 | }
91 |
92 | .complete-booking-button:hover {
93 | background-color: #438e29;
94 | color: white;
95 | transition: background-color 0.5s ease;
96 | cursor: pointer;
97 | }
98 |
99 | .booking-content {
100 | padding-top: 1rem;
101 | border-top: 1px solid #dce0e6
102 | }
103 |
104 | .positive-radio {
105 | padding-left: 0;
106 | }
107 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/completebooking.scss:
--------------------------------------------------------------------------------
1 | .feedback {
2 | margin-bottom: .5rem;
3 | }
4 |
5 | .positive-radio {
6 | list-style: none;
7 | }
8 |
9 | .review-description {
10 | border: 1px solid gray;
11 | border-radius: 4px;
12 | padding: .625em 1em;
13 | font-size: 1em;
14 | font-weight: 200;
15 | width: 92%;
16 | white-space: normal;
17 | min-height: 23px;
18 | margin-bottom: 10px;
19 | margin-top: 10px;
20 | }
21 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/confirm.scss:
--------------------------------------------------------------------------------
1 | .confirmation-container {
2 | padding: 0 2.5rem;
3 | }
4 |
5 | .confirm-result-top-row {
6 | display: flex;
7 | justify-content: space-between;
8 | margin: 1.2rem 0;
9 | }
10 |
11 | .submit-container {
12 | margin-top: 4rem;
13 | }
14 |
15 | .payment-sub {
16 | color: #545e69;
17 | font-size: .875rem;
18 | margin-bottom: 1em;
19 | }
20 |
21 | .payment-container {
22 | display: flex;
23 | flex-direction: column;
24 | color: #545e69;
25 | }
26 |
27 | .payment-input-row {
28 | display: flex;
29 | justify-content: space-between;
30 | font-size: .875rem;
31 | color: black;
32 | font-weight: 200;
33 | border: 1px
34 | }
35 |
36 | .payment-input-row span {
37 | margin-bottom: 3px;
38 | }
39 |
40 | .payment-input-box {
41 | display: flex;
42 | flex-direction: column;
43 | }
44 |
45 | .payment-input-box select {
46 | padding: 0.5em 0.75em;
47 | height: 41px;
48 | font-size: 1em;
49 | margin-right: 10px;
50 | }
51 |
52 | .mm {
53 | width: 60px;
54 | }
55 |
56 | .yyyy {
57 | width: 90px;
58 | }
59 |
60 | .payment-input-box input {
61 | border: 1px solid #b1b9c3;
62 | outline: none;
63 | border-radius: 4px;
64 | font-size: 1em;
65 | font-weight: normal;
66 | height: 22px;
67 | padding: 0.625em 1em;
68 | margin-right: 1em;
69 | }
70 |
71 | .col-lg-2 {
72 | width: 16.6666%
73 | }
74 |
75 | .col-lg-3 {
76 | width: 25%
77 | }
78 |
79 | .col-lg-4 {
80 | width: 33.3333%
81 | }
82 |
83 | .confirm-info {
84 | border-top: 1px solid #dce0e6;
85 | padding-top: 2rem;
86 | margin-top: 3rem;
87 | }
88 |
89 | .date-time-confirm {
90 | width: 50%;
91 | }
92 |
93 | .confirm-tutor-info {
94 | width: 50%;
95 | float: left;
96 | position: relative;
97 | display: flex;
98 | border-left: 1px solid #b1b9c3;
99 |
100 | }
101 |
102 | .confirm-tutor-pic {
103 | margin-left: 3rem;
104 | margin-right: 1.5em;
105 | }
106 |
107 | .confirm-picture {
108 | width: 36px;
109 | height: 36px;
110 | border-radius: 4px;
111 | margin-top: .4em;
112 | }
113 |
114 | .confirm-sub {
115 | color: #545e69;
116 | font-weight: 200;
117 | font-size: .875rem;
118 | }
119 |
120 | .confirmation-date-time {
121 | font-size: 1.125rem;
122 | margin-top: 0.5rem;
123 | font-weight: normal;
124 | margin-bottom: 1.5rem;
125 | }
126 | .confirm-tutor-name {
127 | display: flex;
128 | flex-direction: column;
129 | color: #545e69;
130 | margin-top: .25em;
131 | }
132 |
133 | .tutor-name {
134 | color: black;
135 | font-size: 1.125rem;
136 | }
137 |
138 | .confirm-button-sub-container {
139 | display: flex;
140 | justify-content: center;
141 | margin: 1rem 0;
142 | font-size: .8em;
143 | }
144 |
145 | .confirm-form {
146 | margin-bottom: 1rem;
147 | }
148 |
149 | .confirm-smallprint {
150 | margin: 0 auto;
151 | margin-top: 3rem;
152 | display: flex;
153 | flex-direction: column;
154 | justify-content: center;
155 | align-items: center;
156 | width: 720px;
157 | }
158 |
159 | .confirm-smallprint span {
160 | width: 720px;
161 | margin-bottom: 1.7rem;
162 | color: #545e69;
163 | font-weight: 100;
164 | }
165 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/dashboard.scss:
--------------------------------------------------------------------------------
1 | .dashboard-main-page {
2 | display: flex;
3 | flex-direction: column;
4 | align-items: center;
5 | }
6 |
7 | .dashboard-container {
8 | display: flex;
9 | flex-direction: column;
10 | align-items: center;
11 | margin-top: 1rem;
12 | }
13 |
14 | .row {
15 | min-width: 800px;
16 | }
17 |
18 | .greeting {
19 | margin-bottom: 1rem;
20 | display: flex;
21 | }
22 |
23 | .greeting h1 {
24 | font-weight: 300;
25 | }
26 | .greeting-picture {
27 | height: 75px;
28 | width: 75px;
29 | border-radius: 50%;
30 | margin-right: 3rem;
31 | object-fit: cover;
32 | }
33 | .form-pictures {
34 | width: 1200px;
35 | }
36 |
37 | .tile-container {
38 | min-height: 800px;
39 | display: flex;
40 | flex-wrap: wrap;
41 | }
42 |
43 | .tutor-link-tile {
44 | width: 33.333%
45 | }
46 |
47 | .tutor-link-title Link{
48 |
49 | color: #438e29;
50 | }
51 |
52 | .biology {
53 | background: image-url('biology.jpg');
54 | }
55 |
56 | .chemistry {
57 | background: image-url('chemistry.jpeg');
58 | }
59 |
60 | .coding {
61 | background: image-url('coding.jpg');
62 | }
63 |
64 | .history {
65 | background: image-url('history.jpg');
66 | }
67 |
68 | .physics {
69 | background: image-url('physics.jpeg');
70 | }
71 |
72 | .testprep {
73 | background: image-url('test-prep.jpeg');
74 | }
75 |
76 | .tutor-link-tile {
77 | height: 380px;
78 | width: 380px;
79 | margin-right: 20px;
80 | background-repeat: no-repeat;
81 | background-size: 100%;
82 | display: inline-block;
83 | position: relative;
84 | }
85 |
86 | .flag-container {
87 | position: relative;
88 | z-index: 500;
89 | display: block;
90 | height: 50px;
91 | vertical-align: baseline;
92 | }
93 | .subject-title-sub {
94 | position: absolute;
95 | top: 18rem;
96 | padding: .6em 1.4em;
97 | background-color: rgba(255,255,255,0.75);
98 | color: black;
99 | font-weight: bold;
100 | transition: color 0.5s ease;
101 | transition: background-color 0.5s ease;
102 | }
103 |
104 | .no-booking-available {
105 | margin: 3rem 0;
106 | }
107 |
108 | .hover {
109 | background-color: white;
110 | transition: color 0.5s ease;
111 | transition: background-color 0.5s ease;
112 | color: #438e29;
113 | }
114 |
115 | .created-by {
116 | font-weight: 100;
117 | text-align: right;
118 | width: 100%;
119 | margin-right: 2rem;
120 | }
121 |
122 | .how-to-get-started-container {
123 | margin-bottom: 3rem;
124 | }
125 |
126 | .get-started-step {
127 | display: flex;
128 | }
129 |
130 | .get-started-figure {
131 | margin-right: 1.5em;
132 | margin-top: 1em;
133 | }
134 |
135 | .get-started-icon {
136 | background-color: #67727e;
137 | font-size: 1.25em;
138 | display: inline-block;
139 | height: 40px;
140 | width: 40px;
141 | border-radius: 50%;
142 | text-align: center;
143 | font-weight: 600;
144 | color: white;
145 | margin-top: 7px;
146 | align-items: center;
147 | justify-content: center;
148 | line-height: 43px;
149 | }
150 |
151 | .get-started-title {
152 | font-size: 2rem;
153 | line-height: 1.25;
154 | font-weight: normal;
155 | }
156 |
157 | .get-started-sub {
158 | margin: 0 0 1rem 0;
159 | color: #242a30;
160 | font-family: "Proxima", Arial, Helvetica, sans-serif;
161 | font-weight: 100;
162 | font-size: 1rem;
163 | line-height: 1.5;
164 | }
165 |
166 | .get-started-name {
167 | color: #67727e;
168 | line-height: 1.25;
169 | margin-bottom: .3em;
170 | font-weight: 400;
171 | }
172 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/fbgooglelogin.scss:
--------------------------------------------------------------------------------
1 | .loginBtn {
2 | box-sizing: border-box;
3 | position: relative;
4 | /* width: 13em; - apply for fixed size */
5 | margin: 0.2em;
6 | padding: 0 15px 0 46px;
7 | border: none;
8 | text-align: left;
9 | line-height: 34px;
10 | white-space: nowrap;
11 | border-radius: 0.2em;
12 | font-size: 16px;
13 | color: #FFF;
14 | }
15 | .loginBtn:before {
16 | content: "";
17 | box-sizing: border-box;
18 | position: absolute;
19 | top: 0;
20 | left: 0;
21 | width: 34px;
22 | height: 100%;
23 | }
24 | .loginBtn:focus {
25 | outline: none;
26 | }
27 | .loginBtn:active {
28 | box-shadow: inset 0 0 0 32px rgba(0,0,0,0.1);
29 | }
30 |
31 |
32 | /* Facebook */
33 | .loginBtn--facebook {
34 | background-color: #4C69BA;
35 | background-image: linear-gradient(#4C69BA, #3B55A0);
36 | /*font-family: "Helvetica neue", Helvetica Neue, Helvetica, Arial, sans-serif;*/
37 | text-shadow: 0 -1px 0 #354C8C;
38 | }
39 | .loginBtn--facebook:before {
40 | border-right: #364e92 1px solid;
41 | background: url('https://s3-us-west-2.amazonaws.com/s.cdpn.io/14082/icon_facebook.png') 6px 6px no-repeat;
42 | }
43 | .loginBtn--facebook:hover,
44 | .loginBtn--facebook:focus {
45 | background-color: #5B7BD5;
46 | background-image: linear-gradient(#5B7BD5, #4864B1);
47 | }
48 |
49 |
50 | /* Google */
51 | .loginBtn--google {
52 | /*font-family: "Roboto", Roboto, arial, sans-serif;*/
53 | background: #DD4B39;
54 | }
55 | .loginBtn--google:before {
56 | border-right: #BB3F30 1px solid;
57 | background: url('https://s3-us-west-2.amazonaws.com/s.cdpn.io/14082/icon_google.png') 6px 6px no-repeat;
58 | }
59 | .loginBtn--google:hover,
60 | .loginBtn--google:focus {
61 | background: #E74B37;
62 | }
63 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/google.scss:
--------------------------------------------------------------------------------
1 | #map {
2 | height: 100%;
3 | }
4 | /* Optional: Makes the sample page fill the window. */
5 | html, body {
6 | height: 100%;
7 | margin: 0;
8 | padding: 0;
9 | }
10 | #description {
11 | font-family: Roboto;
12 | font-size: 15px;
13 | font-weight: 300;
14 | }
15 |
16 | #infowindow-content .title {
17 | font-weight: bold;
18 | }
19 |
20 | #infowindow-content {
21 | display: none;
22 | }
23 |
24 | #map #infowindow-content {
25 | display: inline;
26 | }
27 |
28 | .pac-card {
29 | margin: 10px 10px 0 0;
30 | border-radius: 2px 0 0 2px;
31 | box-sizing: border-box;
32 | -moz-box-sizing: border-box;
33 | outline: none;
34 | box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3);
35 | background-color: #fff;
36 | font-family: Roboto;
37 | }
38 |
39 | #pac-container {
40 | padding-bottom: 12px;
41 | margin-right: 12px;
42 | }
43 |
44 | .pac-controls {
45 | display: inline-block;
46 | padding: 5px 11px;
47 | }
48 |
49 | .pac-controls label {
50 | font-family: Roboto;
51 | font-size: 13px;
52 | font-weight: 300;
53 | }
54 |
55 | #pac-input {
56 | background-color: #fff;
57 | font-family: Roboto;
58 | font-size: 15px;
59 | font-weight: 300;
60 | margin-left: 12px;
61 | padding: 0 11px 0 13px;
62 | text-overflow: ellipsis;
63 | width: 400px;
64 | }
65 |
66 | #pac-input:focus {
67 | border-color: #4d90fe;
68 | }
69 |
70 | #title {
71 | color: #fff;
72 | background-color: #4d90fe;
73 | font-size: 25px;
74 | font-weight: 500;
75 | padding: 6px 12px;
76 | }
77 | #target {
78 | width: 345px;
79 | }
80 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/login.scss:
--------------------------------------------------------------------------------
1 | html {
2 | font-family: sans-serif;
3 | }
4 |
5 | body {
6 | height: 100%;
7 | }
8 |
9 | .login-signup-page {
10 | }
11 |
12 | .login-background {
13 | background: image-url('loginpage.jpg');
14 | background-size: cover;
15 | background-position: center center;
16 | background-repeat: no-repeat;
17 | position: absolute;
18 | top: 0;
19 | bottom: 0;
20 | left: 0;
21 | right: 0;
22 | }
23 | .login-signup-panel {
24 | z-index: 10;
25 | }
26 | .login-page-container {
27 | display: flex;
28 | flex-direction: column;
29 | justify-content: space-around;
30 | background: white;
31 | border: 1px solid #dce0e6;
32 | border-radius: 4px;
33 | margin-left: auto !important;
34 | margin-right: auto !important;
35 | position: relative;
36 | height: 450px;
37 | padding: 1.5rem 2rem;
38 | max-width: 400px;
39 | top: -2rem;
40 | margin-top: 75px;
41 | }
42 |
43 | .logo {
44 | height: 50px;
45 | width: 195px;
46 | margin-bottom: 10px;
47 | }
48 |
49 | .login-form {
50 | height: 60%;
51 | max-width: 375px;
52 | display: flex;
53 | flex-direction: column;
54 | justify-content: space-between;
55 | // justify-content: space-around;
56 | }
57 |
58 | .input-container {
59 | display: block;
60 | max-width: 375px;
61 | position: relative;
62 | }
63 |
64 | .input-container label {
65 | font-weight: 100;
66 | font-size: 15px;
67 | }
68 |
69 | .text-input {
70 | outline: none;
71 | border-style: none;
72 | display: flex;
73 | flex-direction: column;
74 | border-color: transparent;
75 | border: 1px solid #b1b9c3;
76 | min-height: 20px;
77 | vertical-align: middle;
78 | border-radius: 4px;
79 | margin-top: 5px;
80 | margin-right: 0;
81 | padding: 0.625em 10em;
82 | width: 97%;
83 | font-size: 1em;
84 | display: block;
85 | }
86 |
87 | .login-button:hover {
88 | background-color: #438e29;
89 | color: white;
90 | transition: background-color 0.5s ease;
91 | cursor: pointer;
92 | }
93 |
94 | .login-button {
95 | margin-left: 10px;
96 | font-size: 1.25rem;
97 | border: 1px solid #51af33;
98 | width: 100%;
99 | background: #51af33;
100 | border-radius: 4px;
101 | padding: 0.6em 4em 0.6em;
102 | text-decoration: none;
103 | color: white;
104 | margin-top: 8px;
105 | transition: background-color 0.5s ease;
106 | margin-bottom: 10px;
107 | }
108 |
109 | .login-signup-link span {
110 | text-decoration: none;
111 | float: right;
112 | color: #51af33;
113 | margin-left: .3rem;
114 | }
115 |
116 | .login-signup-link span:hover {
117 | color: #438e29;
118 | }
119 |
120 | .login-bottom-row {
121 | display: flex;
122 | justify-content: space-between;
123 | align-items: flex-end;
124 | }
125 |
126 | .login-signup-link {
127 | cursor: pointer;
128 | }
129 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/modal.scss:
--------------------------------------------------------------------------------
1 | .signup-modal-title {
2 | font-size: 1.75rem;
3 | line-height: 1.428571429;
4 | margin-bottom: .5rem;
5 | font-weight: 600;
6 | }
7 |
8 | .signup-sub {
9 | margin-bottom: .6rem;
10 | font-weight: 300;
11 | font-size: 1.25rem;
12 | line-height: 1.6;
13 | }
14 |
15 | .modal-container {
16 | display: block;
17 | width: 100%;
18 | position: relative;
19 | }
20 |
21 | .modal-input {
22 | outline: none;
23 | border-style: none;
24 | display: flex;
25 | flex-direction: column;
26 | border-color: transparent;
27 | border: 1px solid #b1b9c3;
28 | min-height: 20px;
29 | vertical-align: middle;
30 | border-radius: 4px;
31 | margin-top: 5px;
32 | margin-bottom: 5px;
33 | padding: 0.625em 0;
34 | width: 91%;
35 | font-size: 1em;
36 | display: block;
37 | padding-left: 2.5em;
38 | }
39 |
40 | .name-container {
41 | display: flex;
42 | }
43 |
44 | .name-container label {
45 | color: #86919d;
46 | cursor: pointer;
47 | font-size: .875rem;
48 | font-weight: 200;
49 | }
50 |
51 | .modal-container label {
52 | color: #86919d;
53 | cursor: pointer;
54 | font-size: .875rem;
55 | font-weight: 200;
56 | }
57 | .name-input-container {
58 | width: 50%;
59 | margin-right: 1.5rem;
60 | position: relative;
61 | }
62 |
63 | .signup-login-link {
64 | cursor: pointer;
65 | margin-left: 0.5rem;
66 | }
67 |
68 | .switch-modal {
69 | display: flex;
70 | margin-top: 1rem;
71 | }
72 |
73 | .modal-icon {
74 | position: absolute;
75 | top: 1.35em;
76 | left: 0;
77 | color: #67727e;
78 | }
79 |
80 | .or {
81 | margin: 1.2rem 0;
82 | text-align: center;
83 | }
84 |
85 | .social-login-container {
86 | display: flex;
87 | justify-content: space-around;
88 | }
89 |
90 | .modal-top-row {
91 | display: flex;
92 | justify-content: space-between;
93 | }
94 |
95 | .modal-close {
96 | cursor: pointer;
97 | }
98 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/searchbar.scss:
--------------------------------------------------------------------------------
1 | #search-results {
2 | position: absolute;
3 | background: white;
4 | margin: 0;
5 | list-style: none;
6 | z-index: 200;
7 | border: 1px solid #dce0e6;
8 | border-bottom-left-radius: 4px;
9 | border-bottom-right-radius: 4px;
10 | box-shadow: 0 2px 4px 1px rgba(177,185,195,0.3);
11 | overflow: hidden;
12 | opacity: 1;
13 | padding-left: 0;
14 | }
15 |
16 | .active {
17 | display: block;
18 | }
19 |
20 | .hidden {
21 | display: none;
22 | }
23 |
24 | .search-result {
25 | cursor: pointer;
26 | min-width: 617px;
27 | color: #438e29;
28 | display: flex;
29 | opacity: 1;
30 | }
31 |
32 | .search-result:hover {
33 | background-color: #f9fafb;
34 | }
35 |
36 | .search-link {
37 | padding: .3em 1.4em;
38 | width: 100%;
39 | text-decoration: none;
40 | color: #438e29;
41 | }
42 |
43 | .search-result-row {
44 | display: flex;
45 | align-items: center;
46 | }
47 |
48 | .search-pic-container {
49 | margin-right: 1.5em;
50 | }
51 |
52 | .search-pic {
53 | height: 60px;
54 | width: 60px;
55 | border-radius: 50%;
56 | }
57 |
58 | .search-pic-Coding {
59 | background: image-url('coding.jpg');
60 | background-size: cover;
61 |
62 | }
63 |
64 | .search-pic-Accounting {
65 | background: image_url('accounting.jpeg');
66 | background-size: cover;
67 |
68 | }
69 |
70 | .search-pic-Physics {
71 | background: image-url('physics.jpeg');
72 | background-size: cover;
73 | }
74 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/show.scss:
--------------------------------------------------------------------------------
1 | .recommendations-container {
2 | display: flex;
3 | margin-top: 2rem;
4 | width: 1200px;
5 | min-height: 800px;
6 | }
7 |
8 | .recommendations-filter-panel {
9 | padding: 1.5rem 2rem;
10 | background: white;
11 | border: 1px solid #dce0e6;
12 | border-radius: 4px;
13 | overflow: hidden;
14 | }
15 |
16 | .recommendations-filter-container {
17 | margin-right: 24px;
18 | max-width: 376px;
19 | min-width: 376px;
20 | flex: 1 1 auto;
21 | }
22 |
23 | .filter-dropdown {
24 | width: 100%;
25 | margin-top: .3rem;
26 | margin-bottom: .75rem;
27 | padding: 0.5em 0.75em;
28 | background-color: white;
29 | height: 46px;
30 | font-size: 1em;
31 | font-weight: 300;
32 | }
33 |
34 | .time-dropdown {
35 | width: 100%;
36 | margin-top: 1.5rem;
37 | margin-bottom: 1.75rem;
38 | padding: 0.5em 0.75em;
39 | background-color: white;
40 | height: 46px;
41 | font-size: 1em;
42 | font-weight: 300;
43 | }
44 |
45 | .recommendations-filter-title {
46 | margin-top: .5rem;
47 | margin-bottom: 1rem;
48 | }
49 |
50 | .datetime-window-container {
51 | display: flex;
52 | flex-direction: row;
53 | overflow: scroll;
54 | }
55 |
56 | .pick-date-window {
57 | min-width: 80px;
58 | height: 80px;
59 | margin: 2px;
60 | }
61 |
62 | .pick-date-window label {
63 | display: flex;
64 | height: 80px;
65 | flex-direction: column;
66 | justify-content: center;
67 | align-items: center;
68 | cursor: pointer;
69 | border: 1px solid #b1b9c3;
70 | border-radius: 4px;
71 | }
72 |
73 | .selected-date {
74 | background-color: #51af33;
75 | border-color: #51af33;
76 | color: white;
77 | cursor: pointer;
78 | border-radius: 4px;
79 | }
80 |
81 | .recommendation-result {
82 | border: 1px solid #dce0e6;
83 | border-radius: 4px;
84 | padding: 2rem;
85 | background: white;
86 | display: flex;
87 | margin-bottom: 2rem;
88 | }
89 |
90 | .recommendations-result-figure {
91 | display: flex;
92 | flex-direction: column;
93 | }
94 |
95 | .result-picture {
96 | width: 200px;
97 | height: 200px;
98 | object-fit: cover;
99 | }
100 |
101 | .recommendations-result-top-row {
102 | display: flex;
103 | justify-content: space-between;
104 | }
105 |
106 | .recommendations-result-content {
107 | display: flex;
108 | flex-direction: column;
109 | margin-left: 2rem;
110 | width: 100%;
111 | }
112 |
113 | .result-name {
114 | font-size: 2rem;
115 | font-weight: bold;
116 | margin-bottom: 0.5rem;
117 | }
118 |
119 | .result-rate {
120 | font-weight: 500;
121 | font-size: 1.5rem;
122 | }
123 |
124 | .blurb-title {
125 | padding-top: 1rem;
126 | border-top: 1px solid #dce0e6;
127 | font-size: 1rem;
128 | font-weight: 600;
129 | }
130 |
131 | .blurb {
132 | font-weight: 100;
133 | margin-top: 0.6rem;
134 | }
135 |
136 | .is-hidden {
137 | display: none;
138 | }
139 |
140 | .none-available {
141 | margin-left: 7rem;
142 | margin-top: 10rem;
143 | font-weight: bold;
144 | font-size: 23px;
145 | }
146 |
147 | .filter-subtitle {
148 | font-weight: 200;
149 | }
150 |
151 | .book-container {
152 | display: flex;
153 | flex-direction: column;
154 | align-items: center;
155 | }
156 | .booking-link {
157 | margin: 1rem 0;
158 | font-size: 1.125rem;
159 | border: 1px solid #51af33;
160 | background: #51af33;
161 | border-radius: 4px;
162 | padding: 0.5625em 1.125em .375em 1.125em;
163 | text-decoration: none;
164 | color: white;
165 | transition: background-color 0.5s ease;
166 | font-weight: 200;
167 | }
168 |
169 | .booking-link:hover {
170 | background-color: #438e29;
171 | color: white;
172 | transition: background-color 0.5s ease;
173 | cursor: pointer;
174 | }
175 |
176 | .result-info {
177 | list-style: none;
178 | position: relative;
179 | padding-left: 0;
180 | }
181 |
182 | .list-icon {
183 | position: absolute;
184 | bottom: 0;
185 | }
186 |
187 | .list-item {
188 | padding-left: 2.8rem;
189 | }
190 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/signup.scss:
--------------------------------------------------------------------------------
1 | html {
2 | font-family: sans-serif;
3 | }
4 |
5 | body {
6 | height: 100%;
7 | }
8 |
9 | .login-signup-page {
10 | }
11 |
12 | .login-background {
13 | background: image-url('loginpage.jpg');
14 | background-size: cover;
15 | background-position: center center;
16 | background-repeat: no-repeat;
17 | position: absolute;
18 | top: 0;
19 | bottom: 0;
20 | left: 0;
21 | right: 0;
22 | height: 1000px;
23 | }
24 | .login-signup-panel {
25 | z-index: 10;
26 | }
27 | .signup-page-container {
28 | display: flex;
29 | flex-direction: column;
30 | justify-content: space-around;
31 | background: white;
32 | border: 1px solid #dce0e6;
33 | border-radius: 4px;
34 | margin-left: auto !important;
35 | margin-right: auto !important;
36 | position: relative;
37 | height: 650px;
38 | padding: 1.5rem 2rem;
39 | max-width: 400px;
40 | top: -2rem;
41 | margin-top: 75px;
42 |
43 | }
44 |
45 | .logo {
46 | height: 50px;
47 | width: 195px;
48 | margin-bottom: 10px;
49 | }
50 |
51 | .signup-form {
52 | height: 100%;
53 | max-width: 375px;
54 | display: flex;
55 | flex-direction: column;
56 | justify-content: space-around;
57 | }
58 |
59 | .input-container {
60 | display: block;
61 | max-width: 375px;
62 | }
63 |
64 | .input-container label {
65 | font-weight: 100;
66 | font-size: 15px;
67 | }
68 |
69 | .text-input {
70 | outline: none;
71 | border-style: none;
72 | display: flex;
73 | flex-direction: column;
74 | border-color: transparent;
75 | border: 1px solid #b1b9c3;
76 | min-height: 20px;
77 | vertical-align: middle;
78 | border-radius: 4px;
79 | margin-top: 5px;
80 | margin-right: 0;
81 | padding: 0.625em 2.5em;
82 | width: 84%;
83 | font-size: 1em;
84 | display: block;
85 | }
86 |
87 | .signup-button:hover {
88 | background-color: #438e29;
89 | color: white;
90 | transition: background-color 0.5s ease;
91 | cursor: pointer;
92 | }
93 |
94 | .signup-button {
95 | margin-left: 10px;
96 | font-size: 1.25rem;
97 | border: 1px solid #51af33;
98 | width: 100%;
99 | background: #51af33;
100 | border-radius: 4px;
101 | padding: 0.6em 4em 0.6em;
102 | text-decoration: none;
103 | color: white;
104 | margin-top: 8px;
105 | transition: background-color 0.5s ease;
106 | margin-bottom: 10px;
107 | }
108 |
109 | .error-msg {
110 | font-size: 10px;
111 | padding-top: 2px;
112 | padding-bottom: 4px;
113 | }
114 |
115 | .signup-login-link span {
116 | text-decoration: none;
117 | float: right;
118 | color: #51af33;
119 | }
120 |
121 | .signup-login-link span:hover {
122 | color: #438e29;
123 | }
124 |
125 | .error-input {
126 | border: 1px solid #f9c339 !important;
127 | }
128 |
129 | .error-msg {
130 | color: #f9c339;
131 | font-size: 10px;
132 | }
133 |
134 | .modal-button {
135 | margin-left: 0;
136 | }
137 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/socialicons.scss:
--------------------------------------------------------------------------------
1 | @font-face {
2 | font-family: 'si';
3 | src: image-url('socicon.eot');
4 | src: image-url('socicon.eot?#iefix') format('embedded-opentype'),
5 | image-url('socicon.woff') format('woff'),
6 | image-url('socicon.ttf') format('truetype'),
7 | image-url('socicon.svg#icomoonregular') format('svg');
8 | font-weight: normal;
9 | font-style: normal;
10 |
11 | }
12 |
13 | @media screen and (-webkit-min-device-pixel-ratio:0) {
14 | @font-face {
15 | font-family:si;
16 | src: url(PATH_TO/socicon.svg) format(svg);
17 | }
18 | }
19 |
20 | .soc {
21 | overflow:hidden;
22 | margin:0; padding:0;
23 | list-style:none;
24 | height: 70px;
25 | }
26 |
27 | .soc li {
28 | display:inline-block;
29 | *display:inline;
30 | zoom:1;
31 | padding: 10px;
32 | }
33 |
34 | .soc li a {
35 | font-family:si!important;
36 | font-style:normal;
37 | font-weight:400;
38 | -webkit-font-smoothing:antialiased;
39 | -moz-osx-font-smoothing:grayscale;
40 | -webkit-box-sizing:border-box;
41 | -moz-box-sizing:border-box;
42 | -ms-box-sizing:border-box;
43 | -o-box-sizing:border-box;
44 | box-sizing:border-box;
45 |
46 | -o-transition:.1s;
47 | -ms-transition:.1s;
48 | -moz-transition:.1s;
49 | -webkit-transition:.1s;
50 | transition:.1s;
51 | -webkit-transition-property: transform;
52 | transition-property: transform;
53 | -webkit-transform: translateZ(0);
54 | transform: translateZ(0);
55 |
56 | overflow:hidden;
57 | text-decoration:none;
58 | text-align:center;
59 | display:block;
60 | position: relative;
61 | z-index: 1;
62 | width: 50px;
63 | height: 50px;
64 | line-height: 50px;
65 | font-size: 23px;
66 | -webkit-border-radius: 10px;
67 | -moz-border-radius: 10px;
68 | border-radius: 10px;
69 | margin-right: 25px;
70 | color: #b1b9c3;
71 | background-color: #ffffff;
72 | }
73 |
74 | .soc a:hover {
75 | z-index: 2;
76 | -webkit-transform: scale(1.1);
77 | transform: scale(1.1);
78 | }
79 |
80 | .soc-icon-last{
81 | margin:0 !important;
82 | }
83 |
84 | .soc-github:before {
85 | content:'\e030';
86 | }
87 | .soc-instagram:before {
88 | content:'\e057';
89 | }
90 | .soc-linkedin:before {
91 | content:'\e049';
92 | }
93 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/taskerform.scss:
--------------------------------------------------------------------------------
1 | .rate-input-container {
2 | margin: .8rem 0;
3 | display: flex;
4 | }
5 |
6 | .rate-input {
7 | border-radius: 4px;
8 | padding: 0.5em 0.75em;
9 | margin: 0 5px;
10 | border-width: 1px;
11 | font-size: 20px;
12 | }
13 |
14 | .rate-symbol {
15 | margin: 14px 0;
16 | }
17 |
18 | .fee {
19 | margin-bottom: 5rem;
20 | }
21 |
--------------------------------------------------------------------------------
/app/channels/application_cable/channel.rb:
--------------------------------------------------------------------------------
1 | module ApplicationCable
2 | class Channel < ActionCable::Channel::Base
3 | end
4 | end
5 |
--------------------------------------------------------------------------------
/app/channels/application_cable/connection.rb:
--------------------------------------------------------------------------------
1 | module ApplicationCable
2 | class Connection < ActionCable::Connection::Base
3 | end
4 | end
5 |
--------------------------------------------------------------------------------
/app/controllers/api/hired_tutors_controller.rb:
--------------------------------------------------------------------------------
1 | class Api::HiredTutorsController < ApplicationController
2 |
3 | def index
4 | @bookings = User.find(params[:user_id]).hired_tutors
5 |
6 | render :index
7 | end
8 |
9 | def show
10 | end
11 |
12 | def create
13 | @booking = HiredTutor.create!(booking_params)
14 | end
15 |
16 | def update
17 | @booking = HiredTutor.find(params[:booking_id])
18 | @booking.update({ completed: true })
19 | end
20 |
21 | def booking_params
22 | params.permit(:user_id, :tutor_id, :subject_id, :rate, :description, :date, :time_period, :location)
23 | end
24 |
25 | end
26 |
--------------------------------------------------------------------------------
/app/controllers/api/reviews_controller.rb:
--------------------------------------------------------------------------------
1 | class Api::ReviewsController < ApplicationController
2 |
3 | def index
4 |
5 | end
6 |
7 | def show
8 | end
9 |
10 | def create
11 | @review = Review.create!(review_params)
12 | end
13 |
14 | def review_params
15 | params.permit(:user_id, :author_id, :subject_id, :body, :positive)
16 | end
17 |
18 | end
19 |
--------------------------------------------------------------------------------
/app/controllers/api/sessions_controller.rb:
--------------------------------------------------------------------------------
1 | class Api::SessionsController < ApplicationController
2 | def create
3 | @user = User.find_by_credentials(
4 | params[:user][:email],
5 | params[:user][:password]
6 | )
7 |
8 | if @user
9 | login(@user)
10 | render "api/users/show"
11 | else
12 | render json: ["Invalid email/password combination"], status: 401
13 | end
14 | end
15 |
16 | def destroy
17 | @user = current_user
18 | if @user
19 | logout
20 | render "api/users/show"
21 | else
22 | render json: ["Nobody signed in"], status: 404
23 | end
24 | end
25 |
26 | def fblogin
27 | @user = User.find_by(email: params[:email])
28 |
29 | if @user
30 | login(@user)
31 | render "api/users/show"
32 | else
33 | render json: ['No account linked to that Email!'], status: 401
34 | end
35 | end
36 | end
37 |
--------------------------------------------------------------------------------
/app/controllers/api/subjects_controller.rb:
--------------------------------------------------------------------------------
1 | class Api::SubjectsController < ApplicationController
2 | def index
3 | @subjects = Subject.all
4 | end
5 |
6 | def create
7 |
8 | end
9 |
10 | def show
11 | end
12 |
13 | private
14 |
15 | end
16 |
--------------------------------------------------------------------------------
/app/controllers/api/tutors_for_hires_controller.rb:
--------------------------------------------------------------------------------
1 | class Api::TutorsForHiresController < ApplicationController
2 |
3 | def index
4 | @tutors = Subject.find(params[:subject_id]).tutors_for_hire.select { |tutor| tutor[params[:ed_lvl]]}
5 | @tutors.map! do |tutor|
6 | user = User.find(tutor.user_id)
7 | {
8 | user: user,
9 | rate: tutor.rate,
10 | num_completed: tutor.num_completed,
11 | description: tutor.description,
12 | times: user.times.map { |time| time[:time] }
13 | }
14 | end
15 | render :index
16 | end
17 |
18 | def create
19 | tutor = TutorsForHire.where({user_id: params[:user_id], subject_id: params[:subject_id]})
20 | if tutor.length > 0
21 | render json: ["You already have signed up to be a tutor for that Subject. To edit, go to your Account page"], status: 401
22 | else
23 | @tutor = TutorsForHire.create!(tutorParams)
24 | end
25 | end
26 |
27 | def show
28 | end
29 |
30 | def tutorParams
31 | params.permit(:user_id, :subject_id, :rate, :description, :first_tier, :second_tier, :third_tier)
32 | end
33 |
34 | end
35 |
--------------------------------------------------------------------------------
/app/controllers/api/users_controller.rb:
--------------------------------------------------------------------------------
1 | class Api::UsersController < ApplicationController
2 | def new
3 | @user = User.new
4 | end
5 |
6 | def create
7 | @user = User.new(user_params)
8 | if @user.save
9 | login(@user)
10 | render :show
11 | else
12 | render json: @user.errors.full_messages, status: 422
13 | end
14 | end
15 |
16 | def update
17 | @user = User.find(params[:user][:id])
18 | if @user.update(user_params)
19 | render :show
20 | else
21 | render json: @user.errors.full_messages, status: 422
22 | end
23 | end
24 |
25 | private
26 | def user_params
27 | params.require(:user).permit(:password, :fname, :lname, :email, :zipcode, :phone_num, :image)
28 | end
29 | end
30 |
--------------------------------------------------------------------------------
/app/controllers/application_controller.rb:
--------------------------------------------------------------------------------
1 | class ApplicationController < ActionController::Base
2 | protect_from_forgery with: :exception
3 |
4 | helper_method :current_user, :logged_in?
5 |
6 | private
7 |
8 | def current_user
9 | return nil unless session[:session_token]
10 | @current_user ||= User.find_by(session_token: session[:session_token])
11 | end
12 |
13 | def logged_in?
14 | !!current_user
15 | end
16 |
17 | def login(user)
18 | user.reset_session_token!
19 | session[:session_token] = user.session_token
20 | @current_user = user
21 | end
22 |
23 | def logout
24 | current_user.reset_session_token!
25 | session[:session_token] = nil
26 | @current_user = nil
27 | end
28 |
29 | def require_logged_in
30 | unless current_user
31 | render json: { base: ['invalid credentials'] }, status: 401
32 | end
33 | end
34 | end
35 |
--------------------------------------------------------------------------------
/app/controllers/concerns/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/victorwu3/Taskable/06e826e3edd0982683390a5bf3ce7f36bc7d8a9f/app/controllers/concerns/.keep
--------------------------------------------------------------------------------
/app/controllers/static_pages_controller.rb:
--------------------------------------------------------------------------------
1 | class StaticPagesController < ApplicationController
2 | def root
3 | end
4 | end
5 |
--------------------------------------------------------------------------------
/app/helpers/application_helper.rb:
--------------------------------------------------------------------------------
1 | module ApplicationHelper
2 | end
3 |
--------------------------------------------------------------------------------
/app/jobs/application_job.rb:
--------------------------------------------------------------------------------
1 | class ApplicationJob < ActiveJob::Base
2 | end
3 |
--------------------------------------------------------------------------------
/app/mailers/application_mailer.rb:
--------------------------------------------------------------------------------
1 | class ApplicationMailer < ActionMailer::Base
2 | default from: 'from@example.com'
3 | layout 'mailer'
4 | end
5 |
--------------------------------------------------------------------------------
/app/models/application_record.rb:
--------------------------------------------------------------------------------
1 | class ApplicationRecord < ActiveRecord::Base
2 | self.abstract_class = true
3 | end
4 |
--------------------------------------------------------------------------------
/app/models/available_time.rb:
--------------------------------------------------------------------------------
1 | # == Schema Information
2 | #
3 | # Table name: available_times
4 | #
5 | # id :integer not null, primary key
6 | # user_id :integer not null
7 | # time_avl :integer not null
8 | # created_at :datetime not null
9 | # updated_at :datetime not null
10 | #
11 |
12 | class AvailableTime < ApplicationRecord
13 | validates :user_id, :time_avl, presence: true
14 |
15 | belongs_to :user
16 | belongs_to :time,
17 | foreign_key: 'time_avl',
18 | class_name: 'TimeOfDay'
19 | end
20 |
--------------------------------------------------------------------------------
/app/models/concerns/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/victorwu3/Taskable/06e826e3edd0982683390a5bf3ce7f36bc7d8a9f/app/models/concerns/.keep
--------------------------------------------------------------------------------
/app/models/hired_tutor.rb:
--------------------------------------------------------------------------------
1 | # == Schema Information
2 | #
3 | # Table name: hired_tutors
4 | #
5 | # id :integer not null, primary key
6 | # user_id :integer not null
7 | # tutor_id :integer not null
8 | # subject_id :integer not null
9 | # rate :integer not null
10 | # description :text not null
11 | # created_at :datetime not null
12 | # updated_at :datetime not null
13 | # date :string
14 | # time_period :string
15 | # location :string
16 | # completed :boolean default(FALSE)
17 | #
18 |
19 | class HiredTutor < ApplicationRecord
20 | validates :user_id, :tutor_id, :subject_id, :date,
21 | :time_period, :rate, :description,
22 | presence: true
23 | validates_inclusion_of :completed, in: [true, false]
24 |
25 | belongs_to :subject
26 | belongs_to :user
27 | belongs_to :tutor,
28 | foreign_key: 'tutor_id',
29 | class_name: 'User'
30 |
31 | end
32 |
--------------------------------------------------------------------------------
/app/models/review.rb:
--------------------------------------------------------------------------------
1 | # == Schema Information
2 | #
3 | # Table name: reviews
4 | #
5 | # id :integer not null, primary key
6 | # user_id :integer not null
7 | # body :text not null
8 | # positive :boolean not null
9 | # created_at :datetime not null
10 | # updated_at :datetime not null
11 | # author_id :integer
12 | # subject_id :integer
13 | #
14 |
15 | class Review < ApplicationRecord
16 | validates :user_id, :positive, presence: true
17 |
18 | belongs_to :user
19 | end
20 |
--------------------------------------------------------------------------------
/app/models/subject.rb:
--------------------------------------------------------------------------------
1 | # == Schema Information
2 | #
3 | # Table name: subjects
4 | #
5 | # id :integer not null, primary key
6 | # title :string not null
7 | # created_at :datetime not null
8 | # updated_at :datetime not null
9 | #
10 |
11 | class Subject < ApplicationRecord
12 | validates :title, presence: true, uniqueness: true
13 |
14 | has_many :tutors_for_hire,
15 | foreign_key: "subject_id",
16 | class_name: 'TutorsForHire'
17 |
18 | has_many :hired_tutors
19 |
20 | end
21 |
--------------------------------------------------------------------------------
/app/models/time_of_day.rb:
--------------------------------------------------------------------------------
1 | # == Schema Information
2 | #
3 | # Table name: time_of_days
4 | #
5 | # id :integer not null, primary key
6 | # time :integer not null
7 | # created_at :datetime not null
8 | # updated_at :datetime not null
9 | #
10 |
11 | class TimeOfDay < ApplicationRecord
12 | end
13 |
--------------------------------------------------------------------------------
/app/models/tutors_for_hire.rb:
--------------------------------------------------------------------------------
1 | # == Schema Information
2 | #
3 | # Table name: tutors_for_hires
4 | #
5 | # id :integer not null, primary key
6 | # user_id :integer not null
7 | # subject_id :integer not null
8 | # num_completed :integer default(0), not null
9 | # rate :integer not null
10 | # description :text not null
11 | # created_at :datetime not null
12 | # updated_at :datetime not null
13 | # first_tier :boolean not null
14 | # second_tier :boolean not null
15 | # third_tier :boolean not null
16 | #
17 |
18 | class TutorsForHire < ApplicationRecord
19 | validates :user_id, :subject_id, :num_completed, :rate, :description, presence: true
20 | validates_inclusion_of :first_tier, :second_tier, :third_tier, in: [true, false]
21 | belongs_to :user
22 | belongs_to :subject
23 |
24 | end
25 |
--------------------------------------------------------------------------------
/app/models/user.rb:
--------------------------------------------------------------------------------
1 | # == Schema Information
2 | #
3 | # Table name: users
4 | #
5 | # id :integer not null, primary key
6 | # email :string not null
7 | # zipcode :string not null
8 | # password_digest :string not null
9 | # phone_num :string not null
10 | # session_token :string not null
11 | # created_at :datetime not null
12 | # updated_at :datetime not null
13 | # fname :string not null
14 | # lname :string not null
15 | # image_file_name :string
16 | # image_content_type :string
17 | # image_file_size :integer
18 | # image_updated_at :datetime
19 | #
20 |
21 | class User < ApplicationRecord
22 | validates :fname, :lname, :email, :zipcode, :password_digest, :phone_num, :session_token, presence: true
23 | validates :email, :session_token, uniqueness: true
24 | validates :password, length: { minimum: 6, allow_nil: true}
25 | validates :email, :fname, :lname, length: { maximum: 45 }
26 | validates :zipcode, length: { is: 5 }
27 | validates :phone_num, length: { minimum: 7, maximum: 15 }
28 |
29 | has_attached_file :image, default_url: ("https://s3.us-east-2.amazonaws.com/app-taskable-pro/default.jpeg")
30 | validates_attachment_content_type :image, content_type: /\Aimage\/.*\z/
31 |
32 | after_initialize :ensure_session_token
33 | attr_reader :password
34 |
35 | has_many :tutors_for_hire,
36 | foreign_key: "user_id",
37 | class_name: 'TutorsForHire'
38 |
39 | has_many :reviews
40 | has_many :hired_tutors
41 | has_many :available_times
42 | has_many :times,
43 | through: :available_times,
44 | source: :time
45 |
46 | def self.find_by_credentials(email, password)
47 | user = User.find_by(email: email)
48 | return nil unless user
49 | user.is_password?(password) ? user : nil
50 | end
51 |
52 | def password=(password)
53 | @password = password
54 | self.password_digest = BCrypt::Password.create(password)
55 | end
56 |
57 | def is_password?(password)
58 | BCrypt::Password.new(self.password_digest).is_password?(password)
59 | end
60 |
61 | def reset_session_token!
62 | generate_unique_session_token
63 | save!
64 | self.session_token
65 | end
66 |
67 | private
68 |
69 | def ensure_session_token
70 | generate_unique_session_token unless self.session_token
71 | end
72 |
73 | def new_session_token
74 | SecureRandom.urlsafe_base64
75 | end
76 |
77 | def generate_unique_session_token
78 | self.session_token = new_session_token
79 | while User.find_by(session_token: self.session_token)
80 | self.session_token = new_session_token
81 | end
82 | self.session_token
83 | end
84 |
85 | end
86 |
--------------------------------------------------------------------------------
/app/views/api/hired_tutors/index.json.jbuilder:
--------------------------------------------------------------------------------
1 | json.array! @bookings do |booking|
2 | json.fname booking.tutor.fname
3 | json.lname booking.tutor.lname
4 | json.id booking.tutor.id
5 | json.rate booking.rate
6 | json.description booking.description
7 | json.date booking.date
8 | json.time_period booking.time_period
9 | json.location booking.location
10 | json.completed booking.completed
11 | json.image_url booking.tutor.image.url
12 | json.subject_id booking.subject_id
13 | json.booking_id booking.id
14 | end
15 |
--------------------------------------------------------------------------------
/app/views/api/tutors_for_hires/index.json.jbuilder:
--------------------------------------------------------------------------------
1 |
2 | json.array! @tutors do |tutor|
3 | json.id tutor[:user][:id]
4 | json.fname tutor[:user][:fname]
5 | json.lname tutor[:user][:lname]
6 | json.rate tutor[:rate]
7 | json.description tutor[:description]
8 | json.num_completed tutor[:num_completed]
9 | json.times tutor[:times]
10 | json.image_url asset_path(tutor[:user].image.url)
11 | end
12 |
--------------------------------------------------------------------------------
/app/views/api/users/_user.json.jbuilder:
--------------------------------------------------------------------------------
1 | json.extract! user, :id, :fname, :lname, :email, :zipcode, :phone_num
2 | json.image_url asset_path(user.image.url)
3 |
--------------------------------------------------------------------------------
/app/views/api/users/show.json.jbuilder:
--------------------------------------------------------------------------------
1 | json.partial! "api/users/user", user: @user
2 |
--------------------------------------------------------------------------------
/app/views/layouts/application.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Taskable
5 |
6 | <%= csrf_meta_tags %>
7 | <%= favicon_link_tag 'favicon.ico' %>
8 |
10 | <%= stylesheet_link_tag 'application', media: 'all' %>
11 | <%= javascript_include_tag 'application' %>
12 |
13 |
14 |
15 |
16 | <%= yield %>
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/app/views/layouts/mailer.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
8 |
9 |
10 |
11 | <%= yield %>
12 |
13 |
14 |
--------------------------------------------------------------------------------
/app/views/layouts/mailer.text.erb:
--------------------------------------------------------------------------------
1 | <%= yield %>
2 |
--------------------------------------------------------------------------------
/app/views/static_pages/root.html.erb:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/bin/bundle:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
3 | load Gem.bin_path('bundler', 'bundle')
4 |
--------------------------------------------------------------------------------
/bin/rails:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | begin
3 | load File.expand_path('../spring', __FILE__)
4 | rescue LoadError => e
5 | raise unless e.message.include?('spring')
6 | end
7 | APP_PATH = File.expand_path('../config/application', __dir__)
8 | require_relative '../config/boot'
9 | require 'rails/commands'
10 |
--------------------------------------------------------------------------------
/bin/rake:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | begin
3 | load File.expand_path('../spring', __FILE__)
4 | rescue LoadError => e
5 | raise unless e.message.include?('spring')
6 | end
7 | require_relative '../config/boot'
8 | require 'rake'
9 | Rake.application.run
10 |
--------------------------------------------------------------------------------
/bin/setup:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | require 'pathname'
3 | require 'fileutils'
4 | include FileUtils
5 |
6 | # path to your application root.
7 | APP_ROOT = Pathname.new File.expand_path('../../', __FILE__)
8 |
9 | def system!(*args)
10 | system(*args) || abort("\n== Command #{args} failed ==")
11 | end
12 |
13 | chdir APP_ROOT do
14 | # This script is a starting point to setup your application.
15 | # Add necessary setup steps to this file.
16 |
17 | puts '== Installing dependencies =='
18 | system! 'gem install bundler --conservative'
19 | system('bundle check') || system!('bundle install')
20 |
21 | # Install JavaScript dependencies if using Yarn
22 | # system('bin/yarn')
23 |
24 |
25 | # puts "\n== Copying sample files =="
26 | # unless File.exist?('config/database.yml')
27 | # cp 'config/database.yml.sample', 'config/database.yml'
28 | # end
29 |
30 | puts "\n== Preparing database =="
31 | system! 'bin/rails db:setup'
32 |
33 | puts "\n== Removing old logs and tempfiles =="
34 | system! 'bin/rails log:clear tmp:clear'
35 |
36 | puts "\n== Restarting application server =="
37 | system! 'bin/rails restart'
38 | end
39 |
--------------------------------------------------------------------------------
/bin/spring:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 |
3 | # This file loads spring without using Bundler, in order to be fast.
4 | # It gets overwritten when you run the `spring binstub` command.
5 |
6 | unless defined?(Spring)
7 | require 'rubygems'
8 | require 'bundler'
9 |
10 | lockfile = Bundler::LockfileParser.new(Bundler.default_lockfile.read)
11 | spring = lockfile.specs.detect { |spec| spec.name == "spring" }
12 | if spring
13 | Gem.use_paths Gem.dir, Bundler.bundle_path.to_s, *Gem.path
14 | gem 'spring', spring.version
15 | require 'spring/binstub'
16 | end
17 | end
18 |
--------------------------------------------------------------------------------
/bin/update:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | require 'pathname'
3 | require 'fileutils'
4 | include FileUtils
5 |
6 | # path to your application root.
7 | APP_ROOT = Pathname.new File.expand_path('../../', __FILE__)
8 |
9 | def system!(*args)
10 | system(*args) || abort("\n== Command #{args} failed ==")
11 | end
12 |
13 | chdir APP_ROOT do
14 | # This script is a way to update your development environment automatically.
15 | # Add necessary update steps to this file.
16 |
17 | puts '== Installing dependencies =='
18 | system! 'gem install bundler --conservative'
19 | system('bundle check') || system!('bundle install')
20 |
21 | puts "\n== Updating database =="
22 | system! 'bin/rails db:migrate'
23 |
24 | puts "\n== Removing old logs and tempfiles =="
25 | system! 'bin/rails log:clear tmp:clear'
26 |
27 | puts "\n== Restarting application server =="
28 | system! 'bin/rails restart'
29 | end
30 |
--------------------------------------------------------------------------------
/bin/yarn:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | VENDOR_PATH = File.expand_path('..', __dir__)
3 | Dir.chdir(VENDOR_PATH) do
4 | begin
5 | exec "yarnpkg #{ARGV.join(" ")}"
6 | rescue Errno::ENOENT
7 | $stderr.puts "Yarn executable was not detected in the system."
8 | $stderr.puts "Download Yarn at https://yarnpkg.com/en/docs/install"
9 | exit 1
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/config/application.rb:
--------------------------------------------------------------------------------
1 | require_relative 'boot'
2 |
3 | require 'rails/all'
4 |
5 | # Require the gems listed in Gemfile, including any gems
6 | # you've limited to :test, :development, or :production.
7 | Bundler.require(*Rails.groups)
8 |
9 | module Taskable
10 | class Application < Rails::Application
11 | # Initialize configuration defaults for originally generated Rails version.
12 | config.load_defaults 5.1
13 |
14 | # Settings in config/environments/* take precedence over those specified here.
15 | # Application configuration should go into files in config/initializers
16 | # -- all .rb files in that directory are automatically loaded.
17 |
18 |
19 | config.paperclip_defaults = {
20 | :storage => :s3,
21 | s3_protocol: :https,
22 | :s3_credentials => {
23 | bucket: ENV["s3_bucket"],
24 | access_key_id: ENV["s3_access_key_id"],
25 | secret_access_key: ENV["s3_secret_access_key"],
26 | s3_host_name: "s3-#{ENV['s3_region']}.amazonaws.com",
27 | s3_region: ENV["s3_region"],
28 | :url => ":s3_host_name"
29 | }
30 | }
31 | end
32 | end
33 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/config/cable.yml:
--------------------------------------------------------------------------------
1 | development:
2 | adapter: async
3 |
4 | test:
5 | adapter: async
6 |
7 | production:
8 | adapter: redis
9 | url: redis://localhost:6379/1
10 | channel_prefix: Taskable_production
11 |
--------------------------------------------------------------------------------
/config/database.yml:
--------------------------------------------------------------------------------
1 | # PostgreSQL. Versions 9.1 and up are supported.
2 | #
3 | # Install the pg driver:
4 | # gem install pg
5 | # On OS X with Homebrew:
6 | # gem install pg -- --with-pg-config=/usr/local/bin/pg_config
7 | # On OS X with MacPorts:
8 | # gem install pg -- --with-pg-config=/opt/local/lib/postgresql84/bin/pg_config
9 | # On Windows:
10 | # gem install pg
11 | # Choose the win32 build.
12 | # Install PostgreSQL and put its /bin directory on your path.
13 | #
14 | # Configure Using Gemfile
15 | # gem 'pg'
16 | #
17 | default: &default
18 | adapter: postgresql
19 | encoding: unicode
20 | # For details on connection pooling, see Rails configuration guide
21 | # http://guides.rubyonrails.org/configuring.html#database-pooling
22 | pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
23 |
24 | development:
25 | <<: *default
26 | database: Taskable_development
27 |
28 | # The specified database role being used to connect to postgres.
29 | # To create additional roles in postgres see `$ createuser --help`.
30 | # When left blank, postgres will use the default role. This is
31 | # the same name as the operating system user that initialized the database.
32 | #username: Taskable
33 |
34 | # The password associated with the postgres role (username).
35 | #password:
36 |
37 | # Connect on a TCP socket. Omitted by default since the client uses a
38 | # domain socket that doesn't need configuration. Windows does not have
39 | # domain sockets, so uncomment these lines.
40 | #host: localhost
41 |
42 | # The TCP port the server listens on. Defaults to 5432.
43 | # If your server runs on a different port number, change accordingly.
44 | #port: 5432
45 |
46 | # Schema search path. The server defaults to $user,public
47 | #schema_search_path: myapp,sharedapp,public
48 |
49 | # Minimum log levels, in increasing order:
50 | # debug5, debug4, debug3, debug2, debug1,
51 | # log, notice, warning, error, fatal, and panic
52 | # Defaults to warning.
53 | #min_messages: notice
54 |
55 | # Warning: The database defined as "test" will be erased and
56 | # re-generated from your development database when you run "rake".
57 | # Do not set this db to the same as development or production.
58 | test:
59 | <<: *default
60 | database: Taskable_test
61 |
62 | # As with config/secrets.yml, you never want to store sensitive information,
63 | # like your database password, in your source code. If your source code is
64 | # ever seen by anyone, they now have access to your database.
65 | #
66 | # Instead, provide the password as a unix environment variable when you boot
67 | # the app. Read http://guides.rubyonrails.org/configuring.html#configuring-a-database
68 | # for a full rundown on how to provide these environment variables in a
69 | # production deployment.
70 | #
71 | # On Heroku and other platform providers, you may have a full connection URL
72 | # available as an environment variable. For example:
73 | #
74 | # DATABASE_URL="postgres://myuser:mypass@localhost/somedatabase"
75 | #
76 | # You can use this database configuration with:
77 | #
78 | # production:
79 | # url: <%= ENV['DATABASE_URL'] %>
80 | #
81 | production:
82 | <<: *default
83 | database: Taskable_production
84 | username: Taskable
85 | password: <%= ENV['TASKABLE_DATABASE_PASSWORD'] %>
86 |
--------------------------------------------------------------------------------
/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 | Rails.application.configure do
2 | # Settings specified here will take precedence over those in config/application.rb.
3 |
4 | # In the development environment your application's code is reloaded on
5 | # every request. This slows down response time but is perfect for development
6 | # since you don't have to restart the web server when you make code changes.
7 | config.cache_classes = false
8 |
9 | # Do not eager load code on boot.
10 | config.eager_load = false
11 |
12 | # Show full error reports.
13 | config.consider_all_requests_local = true
14 |
15 | # Enable/disable caching. By default caching is disabled.
16 | if Rails.root.join('tmp/caching-dev.txt').exist?
17 | config.action_controller.perform_caching = true
18 |
19 | config.cache_store = :memory_store
20 | config.public_file_server.headers = {
21 | 'Cache-Control' => "public, max-age=#{2.days.seconds.to_i}"
22 | }
23 | else
24 | config.action_controller.perform_caching = false
25 |
26 | config.cache_store = :null_store
27 | end
28 |
29 | # Don't care if the mailer can't send.
30 | config.action_mailer.raise_delivery_errors = false
31 |
32 | config.action_mailer.perform_caching = false
33 |
34 | # Print deprecation notices to the Rails logger.
35 | config.active_support.deprecation = :log
36 |
37 | # Raise an error on page load if there are pending migrations.
38 | config.active_record.migration_error = :page_load
39 |
40 | # Debug mode disables concatenation and preprocessing of assets.
41 | # This option may cause significant delays in view rendering with a large
42 | # number of complex assets.
43 | config.assets.debug = true
44 |
45 | # Suppress logger output for asset requests.
46 | config.assets.quiet = true
47 |
48 | # Raises error for missing translations
49 | # config.action_view.raise_on_missing_translations = true
50 |
51 | # Use an evented file watcher to asynchronously detect changes in source code,
52 | # routes, locales, etc. This feature depends on the listen gem.
53 | config.file_watcher = ActiveSupport::EventedFileUpdateChecker
54 | end
55 |
--------------------------------------------------------------------------------
/config/environments/production.rb:
--------------------------------------------------------------------------------
1 | Rails.application.configure do
2 | # Settings specified here will take precedence over those in config/application.rb.
3 |
4 | # Code is not reloaded between requests.
5 | config.cache_classes = true
6 |
7 | # Eager load code on boot. This eager loads most of Rails and
8 | # your application in memory, allowing both threaded web servers
9 | # and those relying on copy on write to perform better.
10 | # Rake tasks automatically ignore this option for performance.
11 | config.eager_load = true
12 |
13 | # Full error reports are disabled and caching is turned on.
14 | config.consider_all_requests_local = false
15 | config.action_controller.perform_caching = true
16 |
17 | # Attempt to read encrypted secrets from `config/secrets.yml.enc`.
18 | # Requires an encryption key in `ENV["RAILS_MASTER_KEY"]` or
19 | # `config/secrets.yml.key`.
20 | config.read_encrypted_secrets = true
21 |
22 | # Disable serving static files from the `/public` folder by default since
23 | # Apache or NGINX already handles this.
24 | config.public_file_server.enabled = ENV['RAILS_SERVE_STATIC_FILES'].present?
25 |
26 | # Compress JavaScripts and CSS.
27 | config.assets.js_compressor = :uglifier
28 | # config.assets.css_compressor = :sass
29 |
30 | # Do not fallback to assets pipeline if a precompiled asset is missed.
31 | config.assets.compile = false
32 |
33 | # `config.assets.precompile` and `config.assets.version` have moved to config/initializers/assets.rb
34 |
35 | # Enable serving of images, stylesheets, and JavaScripts from an asset server.
36 | # config.action_controller.asset_host = 'http://assets.example.com'
37 |
38 | # Specifies the header that your server uses for sending files.
39 | # config.action_dispatch.x_sendfile_header = 'X-Sendfile' # for Apache
40 | # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for NGINX
41 |
42 | # Mount Action Cable outside main process or domain
43 | # config.action_cable.mount_path = nil
44 | # config.action_cable.url = 'wss://example.com/cable'
45 | # config.action_cable.allowed_request_origins = [ 'http://example.com', /http:\/\/example.*/ ]
46 |
47 | # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
48 | # config.force_ssl = true
49 |
50 | # Use the lowest log level to ensure availability of diagnostic information
51 | # when problems arise.
52 | config.log_level = :debug
53 |
54 | # Prepend all log lines with the following tags.
55 | config.log_tags = [ :request_id ]
56 |
57 | # Use a different cache store in production.
58 | # config.cache_store = :mem_cache_store
59 |
60 | # Use a real queuing backend for Active Job (and separate queues per environment)
61 | # config.active_job.queue_adapter = :resque
62 | # config.active_job.queue_name_prefix = "Taskable_#{Rails.env}"
63 | config.action_mailer.perform_caching = false
64 |
65 | # Ignore bad email addresses and do not raise email delivery errors.
66 | # Set this to true and configure the email server for immediate delivery to raise delivery errors.
67 | # config.action_mailer.raise_delivery_errors = false
68 |
69 | # Enable locale fallbacks for I18n (makes lookups for any locale fall back to
70 | # the I18n.default_locale when a translation cannot be found).
71 | config.i18n.fallbacks = true
72 |
73 | # Send deprecation notices to registered listeners.
74 | config.active_support.deprecation = :notify
75 |
76 | # Use default logging formatter so that PID and timestamp are not suppressed.
77 | config.log_formatter = ::Logger::Formatter.new
78 |
79 | # Use a different logger for distributed setups.
80 | # require 'syslog/logger'
81 | # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new 'app-name')
82 |
83 | if ENV["RAILS_LOG_TO_STDOUT"].present?
84 | logger = ActiveSupport::Logger.new(STDOUT)
85 | logger.formatter = config.log_formatter
86 | config.logger = ActiveSupport::TaggedLogging.new(logger)
87 | end
88 |
89 | # Do not dump schema after migrations.
90 | config.active_record.dump_schema_after_migration = false
91 | end
92 |
--------------------------------------------------------------------------------
/config/environments/test.rb:
--------------------------------------------------------------------------------
1 | Rails.application.configure do
2 | # Settings specified here will take precedence over those in config/application.rb.
3 |
4 | # The test environment is used exclusively to run your application's
5 | # test suite. You never need to work with it otherwise. Remember that
6 | # your test database is "scratch space" for the test suite and is wiped
7 | # and recreated between test runs. Don't rely on the data there!
8 | config.cache_classes = true
9 |
10 | # Do not eager load code on boot. This avoids loading your whole application
11 | # just for the purpose of running a single test. If you are using a tool that
12 | # preloads Rails for running tests, you may have to set it to true.
13 | config.eager_load = false
14 |
15 | # Configure public file server for tests with Cache-Control for performance.
16 | config.public_file_server.enabled = true
17 | config.public_file_server.headers = {
18 | 'Cache-Control' => "public, max-age=#{1.hour.seconds.to_i}"
19 | }
20 |
21 | # Show full error reports and disable caching.
22 | config.consider_all_requests_local = true
23 | config.action_controller.perform_caching = false
24 |
25 | # Raise exceptions instead of rendering exception templates.
26 | config.action_dispatch.show_exceptions = false
27 |
28 | # Disable request forgery protection in test environment.
29 | config.action_controller.allow_forgery_protection = false
30 | config.action_mailer.perform_caching = false
31 |
32 | # Tell Action Mailer not to deliver emails to the real world.
33 | # The :test delivery method accumulates sent emails in the
34 | # ActionMailer::Base.deliveries array.
35 | config.action_mailer.delivery_method = :test
36 |
37 | # Print deprecation notices to the stderr.
38 | config.active_support.deprecation = :stderr
39 |
40 | # Raises error for missing translations
41 | # config.action_view.raise_on_missing_translations = true
42 | end
43 |
--------------------------------------------------------------------------------
/config/initializers/application_controller_renderer.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # ActiveSupport::Reloader.to_prepare do
4 | # ApplicationController.renderer.defaults.merge!(
5 | # http_host: 'example.org',
6 | # https: false
7 | # )
8 | # end
9 |
--------------------------------------------------------------------------------
/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 | # Add Yarn node_modules folder to the asset load path.
9 | Rails.application.config.assets.paths << Rails.root.join('node_modules')
10 |
11 | # Precompile additional assets.
12 | # application.js, application.css, and all non-JS/CSS in the app/assets
13 | # folder are already added.
14 | # Rails.application.config.assets.precompile += %w( admin.js admin.css )
15 |
--------------------------------------------------------------------------------
/config/initializers/backtrace_silencers.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces.
4 | # Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ }
5 |
6 | # You can also remove all the silencers if you're trying to debug a problem that might stem from framework code.
7 | # Rails.backtrace_cleaner.remove_silencers!
8 |
--------------------------------------------------------------------------------
/config/initializers/cookies_serializer.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # Specify a serializer for the signed and encrypted cookie jars.
4 | # Valid options are :json, :marshal, and :hybrid.
5 | Rails.application.config.action_dispatch.cookies_serializer = :json
6 |
--------------------------------------------------------------------------------
/config/initializers/filter_parameter_logging.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # Configure sensitive parameters which will be filtered from the log file.
4 | Rails.application.config.filter_parameters += [:password]
5 |
--------------------------------------------------------------------------------
/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/mime_types.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # Add new mime types for use in respond_to blocks:
4 | # Mime::Type.register "text/richtext", :rtf
5 |
--------------------------------------------------------------------------------
/config/initializers/wrap_parameters.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # This file contains settings for ActionController::ParamsWrapper which
4 | # is enabled by default.
5 |
6 | # Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array.
7 | ActiveSupport.on_load(:action_controller) do
8 | wrap_parameters format: [:json]
9 | end
10 |
11 | # To enable root element in JSON for ActiveRecord objects.
12 | # ActiveSupport.on_load(:active_record) do
13 | # self.include_root_in_json = true
14 | # end
15 |
--------------------------------------------------------------------------------
/config/locales/en.yml:
--------------------------------------------------------------------------------
1 | # Files in the config/locales directory are used for internationalization
2 | # and are automatically loaded by Rails. If you want to use locales other
3 | # than 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 | # The following keys must be escaped otherwise they will not be retrieved by
20 | # the default I18n backend:
21 | #
22 | # true, false, on, off, yes, no
23 | #
24 | # Instead, surround them with single quotes.
25 | #
26 | # en:
27 | # 'true': 'foo'
28 | #
29 | # To learn more, please read the Rails Internationalization guide
30 | # available at http://guides.rubyonrails.org/i18n.html.
31 |
32 | en:
33 | hello: "Hello world"
34 |
--------------------------------------------------------------------------------
/config/puma.rb:
--------------------------------------------------------------------------------
1 | # Puma can serve each request in a thread from an internal thread pool.
2 | # The `threads` method setting takes two numbers: a minimum and maximum.
3 | # Any libraries that use thread pools should be configured to match
4 | # the maximum value specified for Puma. Default is set to 5 threads for minimum
5 | # and maximum; this matches the default thread size of Active Record.
6 | #
7 | threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 }
8 | threads threads_count, threads_count
9 |
10 | # Specifies the `port` that Puma will listen on to receive requests; default is 3000.
11 | #
12 | port ENV.fetch("PORT") { 3000 }
13 |
14 | # Specifies the `environment` that Puma will run in.
15 | #
16 | environment ENV.fetch("RAILS_ENV") { "development" }
17 |
18 | # Specifies the number of `workers` to boot in clustered mode.
19 | # Workers are forked webserver processes. If using threads and workers together
20 | # the concurrency of the application would be max `threads` * `workers`.
21 | # Workers do not work on JRuby or Windows (both of which do not support
22 | # processes).
23 | #
24 | # workers ENV.fetch("WEB_CONCURRENCY") { 2 }
25 |
26 | # Use the `preload_app!` method when specifying a `workers` number.
27 | # This directive tells Puma to first boot the application and load code
28 | # before forking the application. This takes advantage of Copy On Write
29 | # process behavior so workers use less memory. If you use this option
30 | # you need to make sure to reconnect any threads in the `on_worker_boot`
31 | # block.
32 | #
33 | # preload_app!
34 |
35 | # If you are preloading your application and using Active Record, it's
36 | # recommended that you close any connections to the database before workers
37 | # are forked to prevent connection leakage.
38 | #
39 | # before_fork do
40 | # ActiveRecord::Base.connection_pool.disconnect! if defined?(ActiveRecord)
41 | # end
42 |
43 | # The code in the `on_worker_boot` will be called if you are using
44 | # clustered mode by specifying a number of `workers`. After each worker
45 | # process is booted, this block will be run. If you are using the `preload_app!`
46 | # option, you will want to use this block to reconnect to any threads
47 | # or connections that may have been created at application boot, as Ruby
48 | # cannot share connections between processes.
49 | #
50 | # on_worker_boot do
51 | # ActiveRecord::Base.establish_connection if defined?(ActiveRecord)
52 | # end
53 | #
54 |
55 | # Allow puma to be restarted by `rails restart` command.
56 | plugin :tmp_restart
57 |
--------------------------------------------------------------------------------
/config/routes.rb:
--------------------------------------------------------------------------------
1 | Rails.application.routes.draw do
2 | # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
3 | root "static_pages#root"
4 |
5 | namespace :api, defaults: { format: :json } do
6 | resources :users, only: [:create, :show, :update, :destroy] do
7 | resources :hired_tutors, only: [:index, :show, :create, :update]
8 | resources :reviews, only: [:index, :show, :create]
9 | resources :available_times, only: [:index, :create]
10 | end
11 | resource :session, only: [:create, :destroy, :show]
12 | post 'fbsession', to: 'sessions#fblogin'
13 | resources :tutors_for_hires, only: [:index, :show, :create, :destroy]
14 | resources :subjects, only: [:index, :show] do
15 | resources :tutors_for_hires, only: [:index, :show, :create]
16 | end
17 | end
18 | end
19 |
--------------------------------------------------------------------------------
/config/secrets.yml:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # Your secret key is used for verifying the integrity of signed cookies.
4 | # If you change this key, all old signed cookies will become invalid!
5 |
6 | # Make sure the secret is at least 30 characters and all random,
7 | # no regular words or you'll be exposed to dictionary attacks.
8 | # You can use `rails secret` to generate a secure secret key.
9 |
10 | # Make sure the secrets in this file are kept private
11 | # if you're sharing your code publicly.
12 |
13 | # Shared secrets are available across all environments.
14 |
15 | # shared:
16 | # api_key: a1B2c3D4e5F6
17 |
18 | # Environmental secrets are only available for that specific environment.
19 |
20 | development:
21 | secret_key_base: 1010d89ced40294e09b97e1e03ca00e8019f20be67269d6a3c8c57f730475ad528bf3ddafa280276c23060e36e7c9b872b9dacc1f9545e31d99f641a7b4ff9f7
22 |
23 | test:
24 | secret_key_base: 7e7a941af5fbdd24c40eb2db7a634df18bd59124080052add3b23c3284a83d42e2ea7dd3a76dc774ca42659599959218aad843702c278f313f40b0b075948dfe
25 |
26 | # Do not keep production secrets in the unencrypted secrets file.
27 | # Instead, either read values from the environment.
28 | # Or, use `bin/rails secrets:setup` to configure encrypted secrets
29 | # and move the `production:` environment over there.
30 |
31 | production:
32 | secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
33 |
--------------------------------------------------------------------------------
/config/spring.rb:
--------------------------------------------------------------------------------
1 | %w(
2 | .ruby-version
3 | .rbenv-vars
4 | tmp/restart.txt
5 | tmp/caching-dev.txt
6 | ).each { |path| Spring.watch(path) }
7 |
--------------------------------------------------------------------------------
/db/migrate/20171024150133_create_users.rb:
--------------------------------------------------------------------------------
1 | class CreateUsers < ActiveRecord::Migration[5.1]
2 | def change
3 | create_table :users do |t|
4 | t.string :name, null: false
5 | t.string :email, null: false
6 | t.string :zipcode, null: false
7 | t.string :password_digest, null: false
8 | t.string :phone_num, null: false
9 | t.string :session_token, null: false
10 |
11 | t.timestamps
12 | end
13 | add_index :users, :name
14 | add_index :users, :email
15 | add_index :users, :session_token
16 | end
17 | end
18 |
--------------------------------------------------------------------------------
/db/migrate/20171024150536_deleteusers.rb:
--------------------------------------------------------------------------------
1 | class Deleteusers < ActiveRecord::Migration[5.1]
2 | def change
3 | drop_table :users
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/db/migrate/20171024150642_addnewusertable.rb:
--------------------------------------------------------------------------------
1 | class Addnewusertable < ActiveRecord::Migration[5.1]
2 | def change
3 | create_table :users do |t|
4 | t.string :name, null: false
5 | t.string :email, null: false, uniqueness: true
6 | t.string :zipcode, null: false
7 | t.string :password_digest, null: false
8 | t.string :phone_num, null: false
9 | t.string :session_token, null: false, uniqueness: true
10 |
11 | t.timestamps
12 | end
13 | add_index :users, :name
14 | add_index :users, :email
15 | add_index :users, :session_token
16 | end
17 | end
18 |
--------------------------------------------------------------------------------
/db/migrate/20171024151058_deletenewusers.rb:
--------------------------------------------------------------------------------
1 | class Deletenewusers < ActiveRecord::Migration[5.1]
2 | def change
3 | drop_table :users
4 |
5 | end
6 | end
7 |
--------------------------------------------------------------------------------
/db/migrate/20171024152237_newusers.rb:
--------------------------------------------------------------------------------
1 | class Newusers < ActiveRecord::Migration[5.1]
2 | def change
3 | create_table :users do |t|
4 | t.string :name, null: false
5 | t.string :email, null: false
6 | t.string :zipcode, null: false
7 | t.string :password_digest, null: false
8 | t.string :phone_num, null: false
9 | t.string :session_token, null: false
10 |
11 | t.timestamps
12 | end
13 | add_index :users, :name
14 | add_index :users, :email, unique: true
15 | add_index :users, :session_token, unique: true
16 | end
17 | end
18 |
--------------------------------------------------------------------------------
/db/migrate/20171024170632_changenames.rb:
--------------------------------------------------------------------------------
1 | class Changenames < ActiveRecord::Migration[5.1]
2 | def change
3 | remove_column :users, :name, :string
4 | add_column :users, :fname, :string, null: false
5 | add_column :users, :lname, :string, null: false
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/db/migrate/20171024212555_create_subjects.rb:
--------------------------------------------------------------------------------
1 | class CreateSubjects < ActiveRecord::Migration[5.1]
2 | def change
3 | create_table :subjects do |t|
4 | t.string :title, null: false
5 |
6 | t.timestamps
7 | end
8 | add_index :subjects, :title
9 | end
10 | end
11 |
--------------------------------------------------------------------------------
/db/migrate/20171024212841_create_tutors_for_hires.rb:
--------------------------------------------------------------------------------
1 | class CreateTutorsForHires < ActiveRecord::Migration[5.1]
2 | def change
3 | create_table :tutors_for_hires do |t|
4 | t.integer :user_id, null: false
5 | t.integer :subject_id, null: false
6 | t.integer :num_completed, null: false, default: 0
7 | t.integer :level, null: false
8 | t.integer :rate, null: false
9 | t.text :description, null: false
10 | t.timestamps
11 | end
12 | end
13 | end
14 |
--------------------------------------------------------------------------------
/db/migrate/20171024214306_create_available_times.rb:
--------------------------------------------------------------------------------
1 | class CreateAvailableTimes < ActiveRecord::Migration[5.1]
2 | def change
3 | create_table :available_times do |t|
4 | t.integer :user_id, null: false
5 | t.integer :time_avl, null: false
6 |
7 | t.timestamps
8 | end
9 | add_index :available_times, :user_id
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/db/migrate/20171024214544_create_hired_tutors.rb:
--------------------------------------------------------------------------------
1 | class CreateHiredTutors < ActiveRecord::Migration[5.1]
2 | def change
3 | create_table :hired_tutors do |t|
4 | t.integer :user_id, null: false
5 | t.integer :tutor_id, null: false
6 | t.integer :subject_id, null: false
7 | t.date :date, null: false
8 | t.integer :time_period, null: false
9 | t.integer :rate, null: false
10 | t.boolean :completed, null: false, default: false
11 | t.text :description, null: false
12 |
13 | t.timestamps
14 | end
15 | add_index :hired_tutors, :user_id
16 | end
17 | end
18 |
--------------------------------------------------------------------------------
/db/migrate/20171024214708_create_reviews.rb:
--------------------------------------------------------------------------------
1 | class CreateReviews < ActiveRecord::Migration[5.1]
2 | def change
3 | create_table :reviews do |t|
4 | t.integer :user_id, null: false
5 | t.text :body, null: false
6 | t.boolean :positive, null: false
7 |
8 | t.timestamps
9 | end
10 | add_index :reviews, :user_id
11 | end
12 | end
13 |
--------------------------------------------------------------------------------
/db/migrate/20171024234541_deletethingsfromtutorstable.rb:
--------------------------------------------------------------------------------
1 | class Deletethingsfromtutorstable < ActiveRecord::Migration[5.1]
2 | def change
3 | remove_column :tutors_for_hires, :level, :integer
4 | add_column :tutors_for_hires, :first_tier, :boolean
5 | add_column :tutors_for_hires, :second_tier, :boolean
6 | add_column :tutors_for_hires, :third_tier, :boolean
7 | end
8 | end
9 |
--------------------------------------------------------------------------------
/db/migrate/20171024234943_updatebooleans.rb:
--------------------------------------------------------------------------------
1 | class Updatebooleans < ActiveRecord::Migration[5.1]
2 | def change
3 | remove_column :tutors_for_hires, :first_tier, :boolean
4 | remove_column :tutors_for_hires, :second_tier, :boolean
5 | remove_column :tutors_for_hires, :third_tier, :boolean
6 | add_column :tutors_for_hires, :first_tier, :boolean, null: false
7 | add_column :tutors_for_hires, :second_tier, :boolean, null: false
8 | add_column :tutors_for_hires, :third_tier, :boolean, null: false
9 | end
10 | end
11 |
--------------------------------------------------------------------------------
/db/migrate/20171027131139_add_attachment_image_to_users.rb:
--------------------------------------------------------------------------------
1 | class AddAttachmentImageToUsers < ActiveRecord::Migration[5.1]
2 | def self.up
3 | change_table :users do |t|
4 | t.attachment :image
5 | end
6 | end
7 |
8 | def self.down
9 | remove_attachment :users, :image
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/db/migrate/20171027193700_create_time_of_days.rb:
--------------------------------------------------------------------------------
1 | class CreateTimeOfDays < ActiveRecord::Migration[5.1]
2 | def change
3 | create_table :time_of_days do |t|
4 | t.integer :time, null: false
5 | t.timestamps
6 | end
7 | add_index :time_of_days, :time
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/db/migrate/20171029231855_changehiredtutors.rb:
--------------------------------------------------------------------------------
1 | class Changehiredtutors < ActiveRecord::Migration[5.1]
2 | def change
3 | remove_column :hired_tutors, :date
4 | remove_column :hired_tutors, :time_period
5 | add_column :hired_tutors, :date, :string
6 | add_column :hired_tutors, :time_period, :string
7 | end
8 | end
9 |
--------------------------------------------------------------------------------
/db/migrate/20171029235356_edit_hiredtutor.rb:
--------------------------------------------------------------------------------
1 | class EditHiredtutor < ActiveRecord::Migration[5.1]
2 | def change
3 | remove_column :hired_tutors, :completed
4 | add_column :hired_tutors, :completed, :boolean
5 | add_column :hired_tutors, :location, :string
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/db/migrate/20171029235954_add_default_completed.rb:
--------------------------------------------------------------------------------
1 | class AddDefaultCompleted < ActiveRecord::Migration[5.1]
2 | def change
3 | remove_column :hired_tutors, :completed
4 | add_column :hired_tutors, :completed, :boolean, default: false
5 | end
6 | end
7 |
--------------------------------------------------------------------------------
/db/migrate/20171101134706_addsubjecttoreview.rb:
--------------------------------------------------------------------------------
1 | class Addsubjecttoreview < ActiveRecord::Migration[5.1]
2 | def change
3 | add_column :reviews, :subject_id, :integer
4 | add_column :reviews, :author_id, :integer
5 | end
6 | end
7 |
--------------------------------------------------------------------------------
/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 | # Note that this schema.rb definition is the authoritative source for your
6 | # database schema. If you need to create the application database on another
7 | # system, you should be using db:schema:load, not running all the migrations
8 | # from scratch. The latter is a flawed and unsustainable approach (the more migrations
9 | # you'll amass, the slower it'll run and the greater likelihood for issues).
10 | #
11 | # It's strongly recommended that you check this file into your version control system.
12 |
13 | ActiveRecord::Schema.define(version: 20171101134706) do
14 |
15 | # These are extensions that must be enabled in order to support this database
16 | enable_extension "plpgsql"
17 |
18 | create_table "available_times", force: :cascade do |t|
19 | t.integer "user_id", null: false
20 | t.integer "time_avl", null: false
21 | t.datetime "created_at", null: false
22 | t.datetime "updated_at", null: false
23 | t.index ["user_id"], name: "index_available_times_on_user_id"
24 | end
25 |
26 | create_table "hired_tutors", force: :cascade do |t|
27 | t.integer "user_id", null: false
28 | t.integer "tutor_id", null: false
29 | t.integer "subject_id", null: false
30 | t.integer "rate", null: false
31 | t.text "description", null: false
32 | t.datetime "created_at", null: false
33 | t.datetime "updated_at", null: false
34 | t.string "date"
35 | t.string "time_period"
36 | t.string "location"
37 | t.boolean "completed", default: false
38 | t.index ["user_id"], name: "index_hired_tutors_on_user_id"
39 | end
40 |
41 | create_table "reviews", force: :cascade do |t|
42 | t.integer "user_id", null: false
43 | t.text "body", null: false
44 | t.boolean "positive", null: false
45 | t.datetime "created_at", null: false
46 | t.datetime "updated_at", null: false
47 | t.integer "subject_id"
48 | t.integer "author_id"
49 | t.index ["user_id"], name: "index_reviews_on_user_id"
50 | end
51 |
52 | create_table "subjects", force: :cascade do |t|
53 | t.string "title", null: false
54 | t.datetime "created_at", null: false
55 | t.datetime "updated_at", null: false
56 | t.index ["title"], name: "index_subjects_on_title"
57 | end
58 |
59 | create_table "time_of_days", force: :cascade do |t|
60 | t.integer "time", null: false
61 | t.datetime "created_at", null: false
62 | t.datetime "updated_at", null: false
63 | t.index ["time"], name: "index_time_of_days_on_time"
64 | end
65 |
66 | create_table "tutors_for_hires", force: :cascade do |t|
67 | t.integer "user_id", null: false
68 | t.integer "subject_id", null: false
69 | t.integer "num_completed", default: 0, null: false
70 | t.integer "rate", null: false
71 | t.text "description", null: false
72 | t.datetime "created_at", null: false
73 | t.datetime "updated_at", null: false
74 | t.boolean "first_tier", null: false
75 | t.boolean "second_tier", null: false
76 | t.boolean "third_tier", null: false
77 | end
78 |
79 | create_table "users", force: :cascade do |t|
80 | t.string "email", null: false
81 | t.string "zipcode", null: false
82 | t.string "password_digest", null: false
83 | t.string "phone_num", null: false
84 | t.string "session_token", null: false
85 | t.datetime "created_at", null: false
86 | t.datetime "updated_at", null: false
87 | t.string "fname", null: false
88 | t.string "lname", null: false
89 | t.string "image_file_name"
90 | t.string "image_content_type"
91 | t.integer "image_file_size"
92 | t.datetime "image_updated_at"
93 | t.index ["email"], name: "index_users_on_email", unique: true
94 | t.index ["session_token"], name: "index_users_on_session_token", unique: true
95 | end
96 |
97 | end
98 |
--------------------------------------------------------------------------------
/frontend/actions/session_actions.js:
--------------------------------------------------------------------------------
1 | import * as SessionApiUtil from '../util/session_api_util';
2 |
3 | export const RECEIVE_CURRENT_USER = 'RECEIVE_CURRENT_USER';
4 | export const RECEIVE_SESSION_ERRORS = 'RECEIVE_SESSION_ERRORS';
5 | export const RECEIVE_AVL_TIMES = 'RECEIVE_AVL_TIMES';
6 | export const CLEAR_ERRORS = 'CLEAR_ERRORS'
7 |
8 |
9 | export const receiveCurrentUser = current_user => {
10 | return ({
11 | type: RECEIVE_CURRENT_USER,
12 | current_user
13 | });
14 | };
15 |
16 | export const receiveErrors = errors => {
17 | return ({
18 | type: RECEIVE_SESSION_ERRORS,
19 | errors
20 | });
21 | };
22 |
23 | export const clearSessionErrors = () => {
24 | return ({
25 | type: CLEAR_ERRORS
26 | });
27 | };
28 |
29 | export const receiveAvlTimes = avlTimes => {
30 | return ({
31 | type: RECEIVE_AVL_TIMES,
32 | avlTimes
33 | });
34 | };
35 |
36 | export const createAvlTimes = (avlTimes) => dispatch => {
37 | return SessionApiUtil.createAvlTimes(avlTimes).then(
38 | (times) => dispatch(receiveAvlTimes(times))
39 | );
40 | };
41 |
42 | export const updateUser = (formData, userId) => dispatch => {
43 | return SessionApiUtil.updateUser(formData, userId).then(
44 | (user) => dispatch(receiveCurrentUser(user))
45 | );
46 | };
47 |
48 | export const signup = user => dispatch => {
49 | return SessionApiUtil.signup(user).then(
50 | (user) => dispatch(receiveCurrentUser(user)),
51 | (errors) => dispatch(receiveErrors(errors)));
52 | };
53 |
54 |
55 | export const login = user => dispatch => {
56 | return SessionApiUtil.login(user).then(
57 | (user) => dispatch(receiveCurrentUser(user)),
58 | (errors) => dispatch(receiveErrors(errors)));
59 | };
60 |
61 | export const logout = () => dispatch => {
62 | return SessionApiUtil.logout().then(
63 | () => dispatch(receiveCurrentUser(null)),
64 | (errors) => dispatch(receiveErrors(errors)));
65 | };
66 |
67 | export const fblogin = email => dispatch => {
68 | return SessionApiUtil.fblogin(email).then(
69 | (user) => dispatch(receiveCurrentUser(user)),
70 | (errors) => dispatch(receiveErrors(errors)));
71 | };
72 |
73 | export const clearErrors = () => dispatch => {
74 | return dispatch(clearSessionErrors());
75 | }
76 |
--------------------------------------------------------------------------------
/frontend/actions/tutor_actions.js:
--------------------------------------------------------------------------------
1 | import * as TutorApiUtil from '../util/tutor_api_util';
2 |
3 | export const RECEIVE_TUTORS = 'RECEIVE_TUTORS';
4 | export const RECEIVE_TUTOR = 'RECEIVE_TUTOR';
5 | export const RECEIVE_BOOKING = 'RECEIVE_BOOKING';
6 | export const RECEIVE_HIRED_TUTORS = 'RECEIVE_HIRED_TUTORS';
7 | export const UPDATE_BOOKING = 'UPDATE_BOOKING';
8 |
9 | export const receiveTutors = (tutors, params) => {
10 | return ({
11 | type: RECEIVE_TUTORS,
12 | tutors,
13 | params
14 | });
15 | };
16 |
17 | export const receiveTutor = (tutor) => {
18 | return ({
19 | type: RECEIVE_TUTOR,
20 | tutor
21 | });
22 | };
23 |
24 | export const receiveBooking = booking => {
25 | return ({
26 | type: RECEIVE_BOOKING,
27 | booking
28 | });
29 | };
30 |
31 | export const receiveHiredTutors = hiredTutors => {
32 | return ({
33 | type: RECEIVE_HIRED_TUTORS,
34 | hiredTutors
35 | });
36 | };
37 |
38 | export const fetchTutors = (params) => dispatch => {
39 | return TutorApiUtil.fetchTutors(params).then(
40 | tutors => dispatch(receiveTutors(tutors, params))
41 | );
42 | };
43 |
44 | export const createBooking = (params) => dispatch => {
45 | return TutorApiUtil.createBooking(params);
46 | };
47 |
48 | export const fetchHiredTutors = (userId) => dispatch => {
49 | return TutorApiUtil.fetchHiredTutors(userId).then(
50 | hiredTutors => dispatch(receiveHiredTutors(hiredTutors))
51 | );
52 | };
53 |
54 | export const createReview = (params) => dispatch => {
55 | return TutorApiUtil.createReview(params);
56 | }
57 |
58 | export const updateBooking = params => dispatch => {
59 | return TutorApiUtil.updateBooking(params);
60 | }
61 |
62 | export const createTutor = params => dispatch => {
63 | return TutorApiUtil.createTutor(params);
64 | }
65 |
--------------------------------------------------------------------------------
/frontend/actions/ui_actions.js:
--------------------------------------------------------------------------------
1 | export const RECEIVE_CURRENT_SUBJECT = "RECEIVE_CURRENT_SUBJECT";
2 | export const UPDATE_FORM = "UPDATE_FORM";
3 |
4 | export const receiveCurrentSubject = currentSubject => {
5 | return ({
6 | type: RECEIVE_CURRENT_SUBJECT,
7 | currentSubject
8 | });
9 | };
10 |
11 | export const receiveForm = form => {
12 | return ({
13 | type: UPDATE_FORM,
14 | form
15 | });
16 | };
17 |
18 | export const updateSubject = subject => dispatch => {
19 | return dispatch(receiveCurrentSubject(subject));
20 | };
21 |
22 | export const updateForm = form => dispatch => {
23 | return dispatch(receiveForm(form));
24 | };
25 |
--------------------------------------------------------------------------------
/frontend/components/App.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import LoginFormContainer from './login_form/login_form_container';
3 | import SignupFormContainer from './signup_form/signup_form_container';
4 | import { Route } from 'react-router-dom';
5 | import { Switch } from 'react-router';
6 | import { AuthRoute, ProtectedRoute } from '../util/auth_route';
7 | import GreetingContainer from './greeting/greeting_container';
8 | import HomepageContainer from './homepage/homepage_container';
9 | import TutorFormContainer from './tutor_form/tutor_form_container';
10 | import DashboardContainer from './dashboard/dashboard_container';
11 | import TutorShowContainer from './tutor_form/tutor_show_container';
12 | import TutorConfirmContainer from './tutor_form/tutor_confirm_container';
13 | import AccountContainer from './account/account_container';
14 | import TaskerFormContainer from './becometasker/tasker_form_container';
15 |
16 | const App = () => (
17 |
18 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 | );
34 |
35 | export default App;
36 |
--------------------------------------------------------------------------------
/frontend/components/account/account.jsx:
--------------------------------------------------------------------------------
1 | import { Link } from 'react-router-dom';
2 | import React from 'react';
3 | import { Route } from 'react-router-dom';
4 | import { Switch } from 'react-router';
5 | import AccountInfoContainer from './account_info_container';
6 | import AccountEditFormContainer from './account_edit_form_container';
7 | import AccountHeader from '../shared/header'
8 |
9 | class Account extends React.Component{
10 |
11 |
12 | render() {
13 | return (
14 |
15 |
16 |
17 |
18 |
19 |
20 | Your Account
21 |
22 |
23 |
24 |
25 |
26 |
27 | Profile
28 | Become a Tasker
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 | );
42 | }
43 | }
44 |
45 |
46 |
47 | export default Account;
48 |
--------------------------------------------------------------------------------
/frontend/components/account/account_container.js:
--------------------------------------------------------------------------------
1 | import { connect } from 'react-redux';
2 | import Account from './account';
3 | import { logout } from '../../actions/session_actions';
4 |
5 |
6 | const mapStateToProps = (state) => {
7 | return { currentUser: state.session.currentUser };
8 | };
9 |
10 | const mapDispatchToProps = (dispatch) => {
11 | return ({
12 | logout: () => dispatch(logout()),
13 | });
14 | };
15 |
16 | export default connect(
17 | mapStateToProps,
18 | mapDispatchToProps
19 | )(Account);
20 |
--------------------------------------------------------------------------------
/frontend/components/account/account_edit_form.jsx:
--------------------------------------------------------------------------------
1 | import { Link } from 'react-router-dom';
2 | import React from 'react';
3 |
4 | class AccountEditForm extends React.Component {
5 | constructor(props){
6 | super(props);
7 | let user = props.currentUser;
8 | this.state = {
9 | email: user.email,
10 | fname: user.fname,
11 | lname: user.lname,
12 | zipcode: user.zipcode,
13 | phone_num: user.phone_num,
14 | imageFile: null,
15 | imageUrl: user.image_url
16 | };
17 | this.handleChange = this.handleChange.bind(this);
18 | this.handleSubmit = this.handleSubmit.bind(this);
19 | this.updateFile = this.updateFile.bind(this);
20 | }
21 |
22 | handleChange(field) {
23 | return (e) => {
24 | this.setState({ [field]: e.target.value });
25 | };
26 | }
27 |
28 | handleSubmit(e) {
29 | const file = this.state.imageFile;
30 | const userId = this.props.currentUser.id;
31 | e.preventDefault();
32 | const user = Object.assign({}, this.state);
33 | const formData = new FormData();
34 | formData.append("user[fname]", this.state.fname);
35 | formData.append("user[lname]", this.state.lname);
36 | formData.append("user[zipcode]", this.state.zipcode);
37 | formData.append("user[email]", this.state.email);
38 | formData.append("user[phone_num]", this.state.phone_num);
39 | formData.append("user[id]", userId);
40 | if (file) formData.append("user[image]", file);
41 | this.props.updateUser(formData, userId).then(() => this.props.history.push('/account'));
42 | }
43 |
44 | updateFile(e) {
45 | var file = e.currentTarget.files[0];
46 | var fileReader = new FileReader();
47 | fileReader.onloadend = () => {
48 | this.setState({ imageFile: file, imageUrl: fileReader.result });
49 | };
50 |
51 | if (file) {
52 | fileReader.readAsDataURL(file);
53 | }
54 | }
55 |
56 | render() {
57 | let user = this.props.currentUser;
58 |
59 | return (
60 |
61 |
62 |
63 | Account
64 |
65 |
Cancel
66 |
67 |
68 |
69 |
70 |
71 |
Upload a new photo
72 |
73 |
100 |
101 |
102 | );
103 | }
104 | }
105 |
106 | export default AccountEditForm;
107 |
--------------------------------------------------------------------------------
/frontend/components/account/account_edit_form_container.js:
--------------------------------------------------------------------------------
1 | import { connect } from 'react-redux';
2 | import AccountEditForm from './account_edit_form';
3 | import { updateUser } from '../../actions/session_actions';
4 |
5 | const mapStateToProps = (state) => {
6 | return { currentUser: state.session.currentUser };
7 | };
8 |
9 | const mapDispatchToProps = dispatch => {
10 | return { updateUser: (params) => dispatch(updateUser(params)) };
11 | };
12 |
13 | export default connect(
14 | mapStateToProps,
15 | mapDispatchToProps
16 | )(AccountEditForm);
17 |
--------------------------------------------------------------------------------
/frontend/components/account/account_edit_form_container.jsx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/victorwu3/Taskable/06e826e3edd0982683390a5bf3ce7f36bc7d8a9f/frontend/components/account/account_edit_form_container.jsx
--------------------------------------------------------------------------------
/frontend/components/account/account_info.jsx:
--------------------------------------------------------------------------------
1 | import { Link } from 'react-router-dom';
2 | import React from 'react';
3 |
4 | class AccountInfo extends React.Component {
5 |
6 |
7 | render() {
8 | let user = this.props.currentUser;
9 |
10 | return (
11 |
12 |
13 |
14 | Account
15 |
16 |
Edit
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 | person
26 | {user.fname.charAt(0).toUpperCase() + user.fname.slice(1)} {user.lname.slice(0,1).toUpperCase() + user.lname.slice(1)}
27 |
28 |
29 | mail_outline
30 | {user.email}
31 |
32 |
33 | phone
34 | {user.phone_num}
35 |
36 |
37 | location_on
38 | {user.zipcode}
39 |
40 |
41 |
42 |
43 |
44 | );
45 | }
46 | }
47 |
48 | export default AccountInfo;
49 |
--------------------------------------------------------------------------------
/frontend/components/account/account_info_container.js:
--------------------------------------------------------------------------------
1 | import { connect } from 'react-redux';
2 | import AccountInfo from './account_info';
3 |
4 | const mapStateToProps = (state) => {
5 | return { currentUser: state.session.currentUser };
6 | };
7 |
8 | export default connect(
9 | mapStateToProps,
10 | null
11 | )(AccountInfo);
12 |
--------------------------------------------------------------------------------
/frontend/components/becometasker/tasker_form_container.js:
--------------------------------------------------------------------------------
1 | import { connect } from 'react-redux';
2 | import TaskerForm from './tasker_form';
3 | import { createTutor } from '../../actions/tutor_actions';
4 | import { logout } from '../../actions/session_actions';
5 |
6 |
7 | const mapStateToProps = (state) => {
8 | return { currentUser: state.session.currentUser };
9 | };
10 |
11 | const mapDispatchToProps = (dispatch) => {
12 | return ({
13 | logout: () => dispatch(logout()),
14 | createTutor: (params) => dispatch(createTutor(params))
15 | });
16 | };
17 |
18 | export default connect(
19 | mapStateToProps,
20 | mapDispatchToProps
21 | )(TaskerForm);
22 |
--------------------------------------------------------------------------------
/frontend/components/dashboard/booking_item.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | class BookingItem extends React.Component {
4 |
5 |
6 |
7 | render() {
8 | let booking = this.props.booking;
9 | return (
10 |
40 | );
41 | }
42 | }
43 |
44 | export default BookingItem;
45 |
--------------------------------------------------------------------------------
/frontend/components/dashboard/complete_booking.jsx:
--------------------------------------------------------------------------------
1 | import Modal from 'react-modal';
2 | import React from 'react';
3 | import { withRouter } from 'react-router-dom';
4 |
5 | class CompleteBooking extends React.Component {
6 |
7 | constructor(props){
8 | super(props);
9 | this.handleSubmit = this.handleSubmit.bind(this);
10 | this.handleChange = this.handleChange.bind(this);
11 | this.state = {
12 | body: "",
13 | positive: true,
14 | author_id: props.author
15 | };
16 | }
17 |
18 | handleChange(field) {
19 | return (e) => {
20 | this.setState({ [field]: e.target.value });
21 | };
22 | }
23 |
24 | handleSubmit(e){
25 | e.preventDefault();
26 | let params = {
27 | user_id: parseInt(localStorage.getItem('reviewUserId')),
28 | author_id: this.state.author_id,
29 | positive: this.state.positive,
30 | body: this.state.body,
31 | subject_id: parseInt(localStorage.getItem('reviewSubjectId')),
32 | booking_id: parseInt(localStorage.getItem('bookingId'))
33 | }
34 | this.props.updateBooking(params).then(this.props.createReview(params).then(()=>this.props.history.push('/')));
35 | }
36 |
37 | render() {
38 | const customStyles = {
39 | overlay : {
40 | position : 'fixed',
41 | top : 0,
42 | left : 0,
43 | right : 0,
44 | bottom : 0,
45 | background: 'rgba(0, 0, 0, 0.5)'
46 | },
47 | content : {
48 | top : '50%',
49 | left : '50%',
50 | right : 'auto',
51 | bottom : 'auto',
52 | marginRight : '-50%',
53 | transform : 'translate(-50%, -50%)',
54 | width: '475px',
55 | height: '400px',
56 | borderRadius : '10px'
57 | }
58 | };
59 |
60 | let booking = this.props.booking;
61 | return (
62 |
68 | Please leave a review.
69 |
88 |
89 | );
90 | }
91 | }
92 |
93 | export default withRouter(CompleteBooking);
94 |
--------------------------------------------------------------------------------
/frontend/components/dashboard/complete_booking_container.js:
--------------------------------------------------------------------------------
1 | import { connect } from 'react-redux';
2 | import CompleteBooking from './complete_booking';
3 | import { createReview, updateBooking } from '../../actions/tutor_actions';
4 |
5 |
6 | const mapStateToProps = (state) => {
7 | return { currentUser: state.session.currentUser };
8 | };
9 |
10 | const mapDispatchToProps = (dispatch) => {
11 | return ({
12 | createReview: (userId) => dispatch(createReview(userId)),
13 | updateBooking: (bookingId) => dispatch(updateBooking(bookingId))
14 | });
15 | };
16 |
17 | export default connect(
18 | mapStateToProps,
19 | mapDispatchToProps
20 | )(CompleteBooking);
21 |
--------------------------------------------------------------------------------
/frontend/components/dashboard/dashboard_container.js:
--------------------------------------------------------------------------------
1 | import { connect } from 'react-redux';
2 | import Dashboard from './dashboard';
3 | import { logout } from '../../actions/session_actions';
4 | import { updateSubject } from '../../actions/ui_actions';
5 | import { fetchHiredTutors } from '../../actions/tutor_actions';
6 |
7 |
8 | const mapStateToProps = (state) => {
9 | return { currentUser: state.session.currentUser, hiredTutors: state.tutors.hiredTutors };
10 | };
11 |
12 | const mapDispatchToProps = (dispatch) => {
13 | return ({
14 | logout: () => dispatch(logout()),
15 | updateSubject: id => dispatch(updateSubject(id)),
16 | fetchHiredTutors: (userId) => dispatch(fetchHiredTutors(userId))
17 | });
18 | };
19 |
20 | export default connect(
21 | mapStateToProps,
22 | mapDispatchToProps
23 | )(Dashboard);
24 |
--------------------------------------------------------------------------------
/frontend/components/dashboard/how_to_get_started.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | class HowToGetStarted extends React.Component {
4 |
5 | render(){
6 | return(
7 |
8 |
How to Get Started
9 |
We're excited to help! Here's how it works:
10 |
11 |
14 |
15 |
16 | Pick a Subject
17 |
18 |
19 | Choose from a list of popular subjects and areas of education
20 |
21 |
22 |
23 |
24 |
27 |
28 |
29 | Get Matched
30 |
31 |
32 | We'll connect you with a skilled Tutor within minutes of your request
33 |
34 |
35 |
36 |
37 |
40 |
41 |
42 | Get Help Now!
43 |
44 |
45 | Choose when and where to meet with your selected tutor
46 |
47 |
48 |
49 |
50 | )
51 | }
52 | }
53 |
54 | export default HowToGetStarted;
55 |
--------------------------------------------------------------------------------
/frontend/components/greeting/greeting.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Link } from 'react-router-dom';
3 | class Greeting extends React.Component{
4 |
5 | render(){
6 | const currentUser = this.props.currentUser;
7 | if (currentUser) {
8 | return(
9 |
10 |
Welcome to Taskable, {currentUser.fname}!
11 | Logout
12 |
13 | );
14 | } else {
15 | return (
);
16 | }
17 | }
18 |
19 | }
20 |
21 | export default Greeting;
22 |
--------------------------------------------------------------------------------
/frontend/components/greeting/greeting_container.js:
--------------------------------------------------------------------------------
1 | import { connect } from 'react-redux';
2 | import Greeting from './greeting';
3 | import { logout } from '../../actions/session_actions';
4 |
5 | const mapStateToProps = (state) => {
6 | return { currentUser: state.session.currentUser };
7 | };
8 |
9 | const mapDispatchToProps = (dispatch) => {
10 | return { logout: () => dispatch(logout()) };
11 | };
12 |
13 | export default connect(
14 | mapStateToProps,
15 | mapDispatchToProps
16 | )(Greeting);
17 |
--------------------------------------------------------------------------------
/frontend/components/homepage/header.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Link } from 'react-router-dom';
3 |
4 | class Header extends React.Component {
5 |
6 | render(){
7 | return(
8 |
23 | )
24 | }
25 | }
26 |
27 | export default Header;
28 |
--------------------------------------------------------------------------------
/frontend/components/homepage/homepage_container.js:
--------------------------------------------------------------------------------
1 | import { connect } from 'react-redux';
2 | import Homepage from './homepage';
3 | import { updateSubject } from '../../actions/ui_actions';
4 |
5 | const mapStateToProps = (state) => {
6 | return { currentUser: state.session.currentUser };
7 | };
8 |
9 | const mapDispatchToProps = dispatch => ({
10 | updateSubject: id => dispatch(updateSubject(id))
11 | });
12 |
13 | export default connect(
14 | mapStateToProps,
15 | mapDispatchToProps
16 | )(Homepage);
17 |
--------------------------------------------------------------------------------
/frontend/components/homepage/how_it_works.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 |
4 | class HowItWorks extends React.Component {
5 |
6 | render(){
7 | return(
8 |
9 |
10 |
11 |
How it Works
12 |
13 |
14 |
15 |
16 |
1
17 |
Tell us where you're struggling
18 |
19 | Choose from a variety of subjects and select the day and time you'd like to meet with a qualified Tutor. Give us the details and we'll find you the help.
20 |
21 |
22 |
23 |
24 |
25 |
2
26 |
Get matched
27 |
28 | Select from a list of qualified and fully vetted tutors. Find the right fit based on qualifications and hourly rates. Find an expert who suits your needs and learning style.
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
3
37 |
Get real results!
38 |
39 | Just like that, your tutor arrives and helps you towards your goal!. When your session is complete, payment will happen seamlessly and securely through the app.
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
The Taskable Satisfaction Pledge
51 |
Trust and safety are our top priority. All Tutors must undergo extensive background and identity checks. Always have peace of mind with our money back guarantee.
52 |
53 |
54 |
55 |
56 |
57 | )
58 | }
59 | }
60 |
61 | export default HowItWorks;
62 |
--------------------------------------------------------------------------------
/frontend/components/homepage/results.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Link } from 'react-router-dom';
3 |
4 |
5 | class Results extends React.Component {
6 |
7 |
8 | render() {
9 | return (
10 |
11 |
12 |
13 |
16 |
{`${this.props.subject[0]}`}
17 |
18 |
19 |
20 | )
21 | }
22 | }
23 |
24 |
25 | export default Results;
26 |
--------------------------------------------------------------------------------
/frontend/components/login_form/login_form_container.js:
--------------------------------------------------------------------------------
1 | import { connect } from 'react-redux';
2 | import LoginForm from './login_form';
3 | import { login, fblogin, clearErrors } from '../../actions/session_actions';
4 |
5 | const mapStateToProps = (state, ownProps) => {
6 | return (
7 | { loggedIn: Boolean(state.session.currentUser),
8 | errors: state.errors.session,
9 | }
10 | );
11 | };
12 |
13 | const mapDispatchToProps = (dispatch, ownProps) => ({
14 | login: user => dispatch(login(user)),
15 | fblogin: email => dispatch(fblogin(email)),
16 | clearErrors: () => dispatch(clearErrors())
17 | });
18 |
19 |
20 | export default connect(
21 | mapStateToProps,
22 | mapDispatchToProps
23 | )(LoginForm);
24 |
--------------------------------------------------------------------------------
/frontend/components/root.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Provider } from 'react-redux';
3 | import { HashRouter } from 'react-router-dom';
4 | import App from './App';
5 |
6 | const Root = ({ store }) => (
7 |
8 |
9 |
10 |
11 |
12 | );
13 |
14 | export default Root;
15 |
--------------------------------------------------------------------------------
/frontend/components/shared/error_handler.jsx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/victorwu3/Taskable/06e826e3edd0982683390a5bf3ce7f36bc7d8a9f/frontend/components/shared/error_handler.jsx
--------------------------------------------------------------------------------
/frontend/components/shared/footer.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Link } from 'react-router-dom';
3 |
4 | const Footer = () => {
5 | return (
6 |
7 |
8 |
Like what you see? Follow me here!
9 |
14 |
15 |
16 |
17 |
18 |
About TaskRabbit
19 |
25 |
26 |
35 |
36 |
37 |
38 |
39 | Created by Victor Wu
40 |
41 | );
42 | };
43 |
44 |
45 | export default Footer;
46 |
--------------------------------------------------------------------------------
/frontend/components/shared/header.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Link } from 'react-router-dom';
3 |
4 | class AccountHeader extends React.Component{
5 |
6 | constructor(props) {
7 | super(props)
8 | }
9 |
10 | render() {
11 | return (
12 |
28 | )
29 |
30 | }
31 |
32 | }
33 |
34 |
35 | export default AccountHeader;
36 |
--------------------------------------------------------------------------------
/frontend/components/shared/trust_banner.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Link } from 'react-router-dom';
3 |
4 | class TrustBanner extends React.Component {
5 |
6 | render() {
7 | let description;
8 | if (this.props.formType === 'form') {
9 | description = 'Satisfaction guaranteed for every tutoring session.';
10 | } else if (this.props.formType === 'show') {
11 | description = 'All Tutors are fully vetted & background checked.';
12 | } else if (this.props.formType === 'confirm') {
13 | description = "You don't pay until your session is completed.";
14 | }
15 | return (
16 |
17 |
18 |
19 |
Trust & Safety Guarantee:
20 |
{description}
21 |
22 |
23 | );
24 | }
25 | }
26 |
27 |
28 | export default TrustBanner;
29 |
--------------------------------------------------------------------------------
/frontend/components/signup_form/signup_form_container.js:
--------------------------------------------------------------------------------
1 | import { connect } from 'react-redux';
2 | import SignupForm from './signup_form';
3 | import { signup, clearErrors } from '../../actions/session_actions';
4 |
5 | const mapStateToProps = (state, ownProps) => {
6 | return (
7 | { loggedIn: Boolean(state.session.currentUser),
8 | errors: state.errors.session,
9 | }
10 | );
11 | };
12 |
13 | const mapDispatchToProps = (dispatch, ownProps) => ({
14 | login: user => dispatch(signup(user)),
15 | clearErrors: () => dispatch(clearErrors())
16 | });
17 |
18 |
19 | export default connect(
20 | mapStateToProps,
21 | mapDispatchToProps
22 | )(SignupForm);
23 |
--------------------------------------------------------------------------------
/frontend/components/tutor_form/date_box_item.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | class DateBoxItem extends React.Component {
4 | constructor(props){
5 | super(props);
6 | }
7 |
8 | render() {
9 | let date = this.props.date;
10 | return (
11 |
12 |
13 |
14 |
15 | {date.day_string}
16 |
17 | {date.date}
18 |
19 |
20 | );
21 | }
22 | }
23 |
24 |
25 | export default DateBoxItem;
26 |
--------------------------------------------------------------------------------
/frontend/components/tutor_form/google/google_autocomplete.js:
--------------------------------------------------------------------------------
1 | export const initAutocomplete = () => {
2 | return new google.maps.places.Autocomplete(
3 | (document.getElementById('autocomplete')), {types: ['geocode', 'establishment']});
4 | };
5 |
6 | export const geolocate = (autocomplete) => {
7 | return (autocomplete) => {
8 | if (navigator.geolocation) {
9 | navigator.geolocation.getCurrentPosition((position) => {
10 | const geolocation = {
11 | lat: position.coords.latitude,
12 | lng: position.coords.longitude
13 | };
14 | const circle = new google.maps.Circle({
15 | center: geolocation,
16 | radius: position.coords.accuracy
17 | });
18 | autocomplete.setBounds(circle.getBounds());
19 | });
20 | }
21 | };
22 | };
23 |
24 |
25 | export const addAptNumToAddress = (address, apt_num) => {
26 | address_components = address.split(",");
27 |
28 | if(apt_num !== "") {
29 | address_components = address_components
30 | .slice(0, 1)
31 | .concat(apt_num, address_components.slice(-3));
32 | }
33 | return address_components.join(",");
34 | };
35 |
36 | export const getLocalityAndAddress = () => {
37 | let place = this.getPlace();
38 | let locality = "";
39 | let componentForm = { locality: 'long_name' };
40 |
41 | for (var i = 0; i < place.address_components.length; i++) {
42 | let addressType = place.address_components[i].types[0];
43 | if (componentForm[addressType]) {
44 | locality = place.address_components[i][componentForm[addressType]];
45 | console.log(locality);
46 | }
47 | }
48 |
49 | return callback({ locality: locality, address: place.formatted_address });
50 | }
51 |
--------------------------------------------------------------------------------
/frontend/components/tutor_form/modals/login_modal.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Modal from 'react-modal';
3 | import { FacebookLogin } from 'react-facebook-login-component';
4 | import { GoogleLogin } from 'react-google-login-component';
5 |
6 | const customStyles = {
7 | overlay : {
8 | position : 'fixed',
9 | top : 0,
10 | left : 0,
11 | right : 0,
12 | bottom : 0,
13 | background: 'rgba(0, 0, 0, 0.5)'
14 | },
15 | content : {
16 | top : '50%',
17 | left : '50%',
18 | right : 'auto',
19 | bottom : 'auto',
20 | marginRight : '-50%',
21 | transform : 'translate(-50%, -50%)',
22 | width: '475px',
23 | height: '400px',
24 | borderRadius : '10px'
25 | }
26 | };
27 |
28 | class LoginModal extends React.Component {
29 | constructor(props) {
30 | super(props);
31 | this.responseFacebook = this.responseFacebook.bind(this);
32 | this.responseGoogle = this.responseGoogle.bind(this);
33 | }
34 |
35 | responseFacebook (response) {
36 | this.props.fblogin(response.email);
37 | }
38 |
39 | responseGoogle (googleUser) {
40 | googleUser = gapi.auth2.getAuthInstance().currentUser.get();
41 | const profile = googleUser.getBasicProfile();
42 | var email = profile.getEmail();
43 | this.props.fblogin(email);
44 | }
45 |
46 | render() {
47 | return (
48 |
54 |
55 |
Please log in to continue.
56 |
close
57 |
58 |
59 |
60 |
Email Address
61 |
mail_outline
62 |
63 |
{this.props.errors.includes('Invalid email/password combination') ? "Invalid Email/Password Combination" : ""}
64 |
65 |
66 | Password
67 | vpn_key
68 |
69 |
70 | Log In
71 |
72 |
Don't have an account?
73 |
74 | Sign up
75 |
76 |
77 |
78 | Demo Login
79 |
80 |
81 |
82 | Or
83 |
84 |
93 |
99 |
100 |
101 |
102 | )
103 | }
104 | }
105 |
106 | export default LoginModal;
107 |
--------------------------------------------------------------------------------
/frontend/components/tutor_form/modals/login_modal_container.js:
--------------------------------------------------------------------------------
1 | import { connect } from 'react-redux';
2 | import LoginModal from './login_modal';
3 | import { fblogin } from '../../../actions/session_actions';
4 |
5 | const mapStateToProps = (state, ownProps) => {
6 | return (
7 | { loggedIn: Boolean(state.session.currentUser),
8 | errors: state.errors.session,
9 | }
10 | );
11 | };
12 |
13 | const mapDispatchToProps = (dispatch, ownProps) => ({
14 | fblogin: email => dispatch(fblogin(email))
15 | });
16 |
17 |
18 | export default connect(
19 | mapStateToProps,
20 | mapDispatchToProps
21 | )(LoginModal);
22 |
--------------------------------------------------------------------------------
/frontend/components/tutor_form/modals/signup_modal.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Modal from 'react-modal';
3 |
4 |
5 | const signupStyles = {
6 | overlay : {
7 | position : 'fixed',
8 | top : 0,
9 | left : 0,
10 | right : 0,
11 | bottom : 0,
12 | background: 'rgba(0, 0, 0, 0.5)'
13 | },
14 | content : {
15 | top : '50%',
16 | left : '50%',
17 | right : 'auto',
18 | bottom : 'auto',
19 | marginRight : '-50%',
20 | transform : 'translate(-50%, -50%)',
21 | maxHeight : '640px',
22 | width : '475px',
23 | borderRadius : '10px'
24 | }
25 | };
26 |
27 | class SignupModal extends React.Component {
28 |
29 |
30 | render() {
31 | return (
32 |
38 |
39 |
Create an Account
40 |
close
41 |
42 | You'll be able to review everything before booking
43 |
44 |
57 |
58 | Email Address
59 | mail_outline
60 |
61 | {this.props.emailError}
62 |
63 |
64 | Password
65 | vpn_key
66 |
67 | {this.props.passwordError}
68 |
69 |
70 | Zip Code
71 | place
72 |
73 | {this.props.zipcodeError}
74 |
75 |
76 | Phone Number
77 | phone
78 |
79 | {this.props.phoneNumError}
80 |
81 | Create Account
82 |
83 |
Have an account?
84 |
85 | Log in
86 |
87 |
88 |
89 |
90 | )
91 | }
92 | }
93 |
94 | export default SignupModal;
95 |
--------------------------------------------------------------------------------
/frontend/components/tutor_form/sorting_container.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 |
4 | class SortingContainer extends React.Component {
5 |
6 | render() {
7 | return (
8 |
9 |
10 |
11 |
12 | Sorted By:
13 |
14 |
15 | Recommended
16 | Price (lowest to highest)
17 | Price (highest to lowest)
18 | Number of Sessions Completed
19 | Most Reviews
20 |
21 |
22 |
23 |
24 | Task Date & Time:
25 |
26 |
27 |
28 | {this.props.dateBoxes}
29 |
30 |
31 |
32 | I'm Flexible
33 | Morning 8AM - 12PM
34 | Afternoon 12PM - 4PM
35 | Evening 4PM - 8PM
36 |
37 |
38 |
39 | You can agree later on an exact start time with your selected Tutor.
40 |
41 |
42 |
43 |
44 |
45 | )
46 | }
47 | }
48 |
49 | export default SortingContainer;
50 |
--------------------------------------------------------------------------------
/frontend/components/tutor_form/tutor_confirm_container.js:
--------------------------------------------------------------------------------
1 | import { connect } from 'react-redux';
2 | import TutorConfirm from './tutor_confirm';
3 | import { fetchTutors, createBooking, fetchHiredTutors } from '../../actions/tutor_actions';
4 |
5 | const mapStateToProps = (state, ownProps) => {
6 | return (
7 | { loggedIn: Boolean(state.session.currentUser),
8 | errors: state.errors.session,
9 | currentSubject: state.ui.currentSubject,
10 | params: state.tutors.params,
11 | tutors: state.tutors.tutors,
12 | formType: state.ui.formType,
13 | currentUser: state.session.currentUser
14 | }
15 | );
16 | };
17 |
18 | const mapDispatchToProps = (dispatch, ownProps) => ({
19 | fetchTutors: params => dispatch(fetchTutors(params)),
20 | createBooking: params => dispatch(createBooking(params)),
21 | fetchHiredTutors: userId => dispatch(fetchHiredTutors(userId))
22 | });
23 |
24 |
25 | export default connect(
26 | mapStateToProps,
27 | mapDispatchToProps
28 | )(TutorConfirm);
29 |
--------------------------------------------------------------------------------
/frontend/components/tutor_form/tutor_form_container.js:
--------------------------------------------------------------------------------
1 | import { connect } from 'react-redux';
2 | import TutorForm from './tutor_form';
3 | import { fetchTutors } from '../../actions/tutor_actions';
4 | import { updateForm } from '../../actions/ui_actions';
5 |
6 | const mapStateToProps = (state, ownProps) => {
7 | return (
8 | { loggedIn: Boolean(state.session.currentUser),
9 | errors: state.errors.session,
10 | currentSubject: state.ui.currentSubject,
11 | params: state.tutors.params,
12 | formType: state.ui.formType
13 | }
14 | );
15 | };
16 |
17 | const mapDispatchToProps = (dispatch, ownProps) => ({
18 | fetchTutors: params => dispatch(fetchTutors(params)),
19 | updateForm: form => dispatch(updateForm(form))
20 | });
21 |
22 |
23 | export default connect(
24 | mapStateToProps,
25 | mapDispatchToProps
26 | )(TutorForm);
27 |
--------------------------------------------------------------------------------
/frontend/components/tutor_form/tutor_list_item.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Link, withRouter } from 'react-router-dom';
3 | export const SUBJECTS = {
4 | '1': 'Math',
5 | '2': 'Chemistry',
6 | '3': 'Biology',
7 | '4': 'English',
8 | '5': 'History',
9 | '6': 'Test Prep',
10 | '7': 'Coding',
11 | '8': 'Accounting',
12 | '9': 'Physics'
13 | };
14 |
15 | class TutorListItem extends React.Component {
16 | constructor(props) {
17 | super(props);
18 | }
19 | render(){
20 | let tutor = this.props.tutor;
21 | return (
22 |
23 |
24 |
25 |
26 |
27 | Select & Continue
28 |
29 |
30 |
31 |
32 |
33 |
34 |
{tutor.fname.charAt(0).toUpperCase() + tutor.fname.slice(1)} {tutor.lname.slice(0,1).toUpperCase()}.
35 |
${tutor.rate}/hr
36 |
37 |
38 | done {tutor.num_completed} Completed {SUBJECTS[JSON.parse(localStorage.getItem('currentSubject'))]} tutor sessions
39 |
40 |
41 | How I can help:
42 |
43 |
{tutor.description}
44 |
45 |
46 |
47 | );
48 | }
49 |
50 | }
51 |
52 |
53 |
54 | export default TutorListItem;
55 |
--------------------------------------------------------------------------------
/frontend/components/tutor_form/tutor_show_container.js:
--------------------------------------------------------------------------------
1 | import { connect } from 'react-redux';
2 | import TutorShow from './tutor_show';
3 | import { fetchTutors } from '../../actions/tutor_actions';
4 | import { login, signup, clearErrors } from '../../actions/session_actions';
5 |
6 | const mapStateToProps = (state, ownProps) => {
7 | return (
8 | { loggedIn: Boolean(state.session.currentUser),
9 | errors: state.errors.session,
10 | currentSubject: state.ui.currentSubject,
11 | params: state.tutors.params,
12 | tutors: state.tutors.tutors,
13 | formType: state.ui.formType
14 | }
15 | );
16 | };
17 |
18 | const mapDispatchToProps = (dispatch, ownProps) => ({
19 | fetchTutors: params => dispatch(fetchTutors(params)),
20 | login: user => dispatch(login(user)),
21 | signup: user => dispatch(signup(user)),
22 | clearErrors: () => dispatch(clearErrors())
23 | });
24 |
25 |
26 | export default connect(
27 | mapStateToProps,
28 | mapDispatchToProps
29 | )(TutorShow);
30 |
--------------------------------------------------------------------------------
/frontend/reducers/errors_reducer.js:
--------------------------------------------------------------------------------
1 | import { combineReducers } from 'redux';
2 | import SessionErrorsReducer from './session_errors_reducer';
3 |
4 | const ErrorsReducer = combineReducers({
5 | session: SessionErrorsReducer
6 | });
7 |
8 | export default ErrorsReducer;
9 |
--------------------------------------------------------------------------------
/frontend/reducers/root_reducer.js:
--------------------------------------------------------------------------------
1 | import { combineReducers } from 'redux';
2 | import ErrorsReducer from './errors_reducer';
3 | import SessionReducer from './session_reducer';
4 | import UiReducer from './ui_reducer.js';
5 | import TutorsReducer from './tutors_reducer';
6 |
7 | const RootReducer = combineReducers({
8 | session: SessionReducer,
9 | errors: ErrorsReducer,
10 | ui: UiReducer,
11 | tutors: TutorsReducer
12 | });
13 |
14 |
15 | export default RootReducer;
16 |
--------------------------------------------------------------------------------
/frontend/reducers/session_errors_reducer.js:
--------------------------------------------------------------------------------
1 | import { RECEIVE_SESSION_ERRORS, RECEIVE_CURRENT_USER, CLEAR_ERRORS } from '../actions/session_actions';
2 | import merge from 'lodash/merge';
3 |
4 |
5 | const SessionErrorsReducer = (state = [], action) => {
6 | Object.freeze(state);
7 | switch (action.type) {
8 | case RECEIVE_SESSION_ERRORS:
9 | return action.errors.responseJSON;
10 | case RECEIVE_CURRENT_USER:
11 | return [];
12 | case CLEAR_ERRORS:
13 | return [];
14 | default:
15 | return state;
16 | }
17 | };
18 |
19 | export default SessionErrorsReducer;
20 |
--------------------------------------------------------------------------------
/frontend/reducers/session_reducer.js:
--------------------------------------------------------------------------------
1 | import { RECEIVE_CURRENT_USER, RECEIVE_AVL_TIMES } from '../actions/session_actions';
2 | import merge from 'lodash/merge';
3 | const defaultState = { currentUser: null, avlTimes: null };
4 |
5 |
6 | const SessionReducer = (state = defaultState, action) => {
7 | Object.freeze(state);
8 | switch (action.type) {
9 | case RECEIVE_CURRENT_USER:
10 | return merge({}, state, { currentUser: action.current_user });
11 | case RECEIVE_AVL_TIMES:
12 | return merge({}, state, { avlTimes: action.avlTimes })
13 | default:
14 | return state;
15 | }
16 | };
17 |
18 | export default SessionReducer;
19 |
--------------------------------------------------------------------------------
/frontend/reducers/tutors_reducer.js:
--------------------------------------------------------------------------------
1 | import { RECEIVE_CURRENT_USER } from '../actions/session_actions';
2 | import { RECEIVE_TUTORS, RECEIVE_HIRED_TUTORS } from '../actions/tutor_actions';
3 | import merge from 'lodash/merge';
4 |
5 | let defaultState = {tutors: null, params: {address: null, ed_lvl: null, description: null}, hiredTutors: null};
6 |
7 | const TutorsReducer = (state = defaultState, action) => {
8 | Object.freeze(state);
9 | switch (action.type) {
10 | case RECEIVE_TUTORS:
11 | return merge({}, state, {params: action.params}, {tutors: action.tutors});
12 | case RECEIVE_HIRED_TUTORS:
13 | return merge({}, state, {hiredTutors: action.hiredTutors});
14 | case RECEIVE_CURRENT_USER:
15 | return { hiredTutors: [] };
16 | default:
17 | return state;
18 | }
19 | };
20 |
21 | export default TutorsReducer;
22 |
--------------------------------------------------------------------------------
/frontend/reducers/ui_reducer.js:
--------------------------------------------------------------------------------
1 | import { RECEIVE_CURRENT_SUBJECT, UPDATE_FORM } from '../actions/ui_actions';
2 | import merge from 'lodash/merge';
3 |
4 | const UiReducer = (state = { currentSubject: 0, formType: 'form' }, action) => {
5 | Object.freeze(state);
6 | switch(action.type) {
7 | case RECEIVE_CURRENT_SUBJECT:
8 | return merge({}, state, { currentSubject: action.currentSubject });
9 | case UPDATE_FORM:
10 | return merge({}, state, { formType: action.form });
11 | default: return state;
12 | }
13 | };
14 |
15 | export default UiReducer;
16 |
--------------------------------------------------------------------------------
/frontend/store/store.js:
--------------------------------------------------------------------------------
1 | import { createStore, applyMiddleware } from 'redux';
2 | import RootReducer from '../reducers/root_reducer';
3 | import logger from 'redux-logger';
4 | import thunk from 'redux-thunk';
5 |
6 | const middlewares = [thunk];
7 |
8 | if (process.env.NODE_ENV !== 'production') {
9 | // must use 'require' (import only allowed at top of file)
10 | const { logger } = require('redux-logger');
11 | middlewares.push(logger);
12 | }
13 |
14 |
15 | const configureStore = (preloadedState = {}) => (
16 | createStore(
17 | RootReducer,
18 | preloadedState,
19 | applyMiddleware(...middlewares)
20 | )
21 | );
22 |
23 | export default configureStore;
24 |
--------------------------------------------------------------------------------
/frontend/taskable.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import { signup, login, logout } from './actions/session_actions';
4 | import configureStore from './store/store';
5 | import Root from './components/root';
6 |
7 | document.addEventListener('DOMContentLoaded', () => {
8 |
9 |
10 | let store;
11 | if (window.currentUser) {
12 | const preloadedState = { session: { currentUser: window.currentUser } };
13 | store = configureStore(preloadedState);
14 | delete window.currentUser;
15 | } else {
16 | store = configureStore();
17 | }
18 |
19 | const root = document.getElementById('root');
20 | ReactDOM.render( , root);
21 | });
22 |
--------------------------------------------------------------------------------
/frontend/util/auth_route.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Route, Redirect, withRouter } from 'react-router-dom';
3 | import { connect } from 'react-redux';
4 |
5 | const Auth = ({component: Component, path, loggedIn}) => (
6 | (
7 | !loggedIn ? (
8 |
9 | ) : (
10 |
11 | )
12 | )}/>
13 | );
14 |
15 | const Protected = ({component: Component, path, loggedIn}) => (
16 | (
17 | loggedIn ? (
18 |
19 | ) : (
20 |
21 | )
22 | )}/>
23 | );
24 |
25 | const Times = ({component: Component, path, loggedIn}) => (
26 | (
27 | loggedIn ? (
28 |
29 | ) : (
30 |
31 | )
32 | )}/>
33 | );
34 |
35 |
36 |
37 | const mapStateToProps = state => {
38 | return {loggedIn: Boolean(state.session.currentUser),
39 | avlTimes: Boolean(state.session.avlTimes)
40 | };
41 | };
42 |
43 | export const AuthRoute = withRouter(connect(mapStateToProps, null)(Auth));
44 |
45 | export const ProtectedRoute = withRouter(connect(mapStateToProps, null)(Protected));
46 |
47 | export const TimesRoute = withRouter(connect(mapStateToProps, null)(Times));
48 |
--------------------------------------------------------------------------------
/frontend/util/session_api_util.js:
--------------------------------------------------------------------------------
1 | export const login = user => (
2 | $.ajax({
3 | method: 'POST',
4 | url: '/api/session',
5 | data: {user: user}
6 | })
7 | );
8 |
9 | export const signup = user => (
10 | $.ajax({
11 | method: 'POST',
12 | url: '/api/users',
13 | data: {user: user}
14 | })
15 | );
16 |
17 | export const logout = () => (
18 | $.ajax({
19 | method: 'DELETE',
20 | url: '/api/session'
21 | })
22 | );
23 |
24 | export const fblogin = email => (
25 | $.ajax({
26 | method: 'POST',
27 | url: '/api/fbsession',
28 | data: {email: email}
29 | })
30 | );
31 |
32 | export const updateUser = (formData, userId) => (
33 | $.ajax({
34 | method: 'PATCH',
35 | url: `/api/users/${userId}`,
36 | processData: false,
37 | contentType: false,
38 | data: formData
39 | })
40 | );
41 |
42 | export const createAvlTimes = avlTimes => (
43 | $.ajax({
44 | method: 'post',
45 | // TODO: interpolate user id
46 | url: '/api/users/:user_id/available_times',
47 | data: avlTimes
48 | })
49 | );
50 |
--------------------------------------------------------------------------------
/frontend/util/tutor_api_util.js:
--------------------------------------------------------------------------------
1 | export const fetchTutors = params => (
2 | $.ajax({
3 | method: 'get',
4 | url: `/api/subjects/${params.currentSubject}/tutors_for_hires/`,
5 | data: params
6 | })
7 | );
8 |
9 | export const createBooking = params => (
10 | $.ajax({
11 | method: 'post',
12 | url: `/api/users/${params.user_id}/hired_tutors`,
13 | data: params
14 | })
15 | );
16 |
17 | export const fetchHiredTutors = userId => (
18 | $.ajax({
19 | method: 'get',
20 | url: `/api/users/${userId}/hired_tutors`
21 | })
22 | );
23 |
24 | export const createReview = params => (
25 | $.ajax({
26 | method: 'post',
27 | url: `/api/users/${params.author_id}/reviews`,
28 | data: params
29 | })
30 | )
31 |
32 | export const updateBooking = params => (
33 | $.ajax({
34 | method: 'patch',
35 | url: `/api/users/${params.user_id}/hired_tutors/${params.booking_id}`,
36 | data: params
37 | })
38 | )
39 |
40 | export const createTutor = params => (
41 | $.ajax({
42 | method: 'post',
43 | url: `/api/subjects/${params.subject_id}/tutors_for_hires`,
44 | data: params
45 | })
46 | )
47 |
--------------------------------------------------------------------------------
/lib/assets/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/victorwu3/Taskable/06e826e3edd0982683390a5bf3ce7f36bc7d8a9f/lib/assets/.keep
--------------------------------------------------------------------------------
/lib/tasks/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/victorwu3/Taskable/06e826e3edd0982683390a5bf3ce7f36bc7d8a9f/lib/tasks/.keep
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Taskable",
3 | "private": true,
4 | "engines": {
5 | "node": "6.10.1",
6 | "npm": "3.10.10"
7 | },
8 | "dependencies": {
9 | "babel-core": "^6.26.0",
10 | "babel-loader": "^7.1.2",
11 | "babel-preset-env": "^1.6.1",
12 | "babel-preset-es2015": "^6.24.1",
13 | "babel-preset-react": "^6.24.1",
14 | "google-maps-react": "^1.1.0",
15 | "material-design-icons": "^3.0.1",
16 | "react": "^16.0.0",
17 | "react-dom": "^16.0.0",
18 | "react-facebook-login-component": "^0.9.1",
19 | "react-google-autocomplete": "^1.0.15",
20 | "react-google-login-component": "^0.9.2",
21 | "react-list": "^0.8.8",
22 | "react-modal": "^3.1.0",
23 | "react-places-autocomplete": "^5.4.3",
24 | "react-redux": "^5.0.6",
25 | "react-router-dom": "^4.2.2",
26 | "react-router-with-props": "^0.1.1",
27 | "react-transition-group": "^2.2.1",
28 | "redux": "^3.7.2",
29 | "redux-logger": "^3.0.6",
30 | "redux-thunk": "^2.2.0",
31 | "typed.js": "^2.0.6",
32 | "webpack": "^3.8.1"
33 | },
34 | "description": "This README would normally document whatever steps are necessary to get the application up and running.",
35 | "version": "1.0.0",
36 | "main": "webpack.config.js",
37 | "directories": {
38 | "test": "test"
39 | },
40 | "scripts": {
41 | "test": "echo \"Error: no test specified\" && exit 1",
42 | "postinstall": "webpack"
43 | },
44 | "keywords": [],
45 | "author": "",
46 | "license": "ISC",
47 | "devDependencies": {
48 | "inline-environment-variables-webpack-plugin": "^1.2.1"
49 | },
50 | "repository": {
51 | "type": "git",
52 | "url": "git+https://github.com/victorwu3/Taskable.git"
53 | },
54 | "bugs": {
55 | "url": "https://github.com/victorwu3/Taskable/issues"
56 | },
57 | "homepage": "https://github.com/victorwu3/Taskable#readme"
58 | }
59 |
--------------------------------------------------------------------------------
/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/victorwu3/Taskable/06e826e3edd0982683390a5bf3ce7f36bc7d8a9f/public/apple-touch-icon-precomposed.png
--------------------------------------------------------------------------------
/public/apple-touch-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/victorwu3/Taskable/06e826e3edd0982683390a5bf3ce7f36bc7d8a9f/public/apple-touch-icon.png
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/victorwu3/Taskable/06e826e3edd0982683390a5bf3ce7f36bc7d8a9f/public/favicon.ico
--------------------------------------------------------------------------------
/public/robots.txt:
--------------------------------------------------------------------------------
1 | # See http://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file
2 |
--------------------------------------------------------------------------------
/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/victorwu3/Taskable/06e826e3edd0982683390a5bf3ce7f36bc7d8a9f/test/controllers/.keep
--------------------------------------------------------------------------------
/test/fixtures/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/victorwu3/Taskable/06e826e3edd0982683390a5bf3ce7f36bc7d8a9f/test/fixtures/.keep
--------------------------------------------------------------------------------
/test/fixtures/available_times.yml:
--------------------------------------------------------------------------------
1 | # == Schema Information
2 | #
3 | # Table name: available_times
4 | #
5 | # id :integer not null, primary key
6 | # user_id :integer not null
7 | # time_avl :integer not null
8 | # created_at :datetime not null
9 | # updated_at :datetime not null
10 | #
11 |
12 | # Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html
13 |
14 | one:
15 | user_id: 1
16 | time_avl: 1
17 |
18 | two:
19 | user_id: 1
20 | time_avl: 1
21 |
--------------------------------------------------------------------------------
/test/fixtures/files/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/victorwu3/Taskable/06e826e3edd0982683390a5bf3ce7f36bc7d8a9f/test/fixtures/files/.keep
--------------------------------------------------------------------------------
/test/fixtures/hired_tutors.yml:
--------------------------------------------------------------------------------
1 | # == Schema Information
2 | #
3 | # Table name: hired_tutors
4 | #
5 | # id :integer not null, primary key
6 | # user_id :integer not null
7 | # tutor_id :integer not null
8 | # subject_id :integer not null
9 | # rate :integer not null
10 | # description :text not null
11 | # created_at :datetime not null
12 | # updated_at :datetime not null
13 | # date :string
14 | # time_period :string
15 | # location :string
16 | # completed :boolean default(FALSE)
17 | #
18 |
19 | # Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html
20 |
21 | one:
22 | user_id: 1
23 | tutor_id: 1
24 | subject_id: 1
25 | date: 2017-10-24
26 | time_period: 1
27 | rate: 1
28 | completed: false
29 | description: MyText
30 |
31 | two:
32 | user_id: 1
33 | tutor_id: 1
34 | subject_id: 1
35 | date: 2017-10-24
36 | time_period: 1
37 | rate: 1
38 | completed: false
39 | description: MyText
40 |
--------------------------------------------------------------------------------
/test/fixtures/reviews.yml:
--------------------------------------------------------------------------------
1 | # == Schema Information
2 | #
3 | # Table name: reviews
4 | #
5 | # id :integer not null, primary key
6 | # user_id :integer not null
7 | # body :text not null
8 | # positive :boolean not null
9 | # created_at :datetime not null
10 | # updated_at :datetime not null
11 | # author_id :integer
12 | # subject_id :integer
13 | #
14 |
15 | # Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html
16 |
17 | one:
18 | user_id: 1
19 | body: MyText
20 | positive: false
21 |
22 | two:
23 | user_id: 1
24 | body: MyText
25 | positive: false
26 |
--------------------------------------------------------------------------------
/test/fixtures/subjects.yml:
--------------------------------------------------------------------------------
1 | # == Schema Information
2 | #
3 | # Table name: subjects
4 | #
5 | # id :integer not null, primary key
6 | # title :string not null
7 | # created_at :datetime not null
8 | # updated_at :datetime not null
9 | #
10 |
11 | # Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html
12 |
13 | one:
14 | title: MyString
15 |
16 | two:
17 | title: MyString
18 |
--------------------------------------------------------------------------------
/test/fixtures/time_of_days.yml:
--------------------------------------------------------------------------------
1 | # == Schema Information
2 | #
3 | # Table name: time_of_days
4 | #
5 | # id :integer not null, primary key
6 | # time :integer not null
7 | # created_at :datetime not null
8 | # updated_at :datetime not null
9 | #
10 |
11 | # Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html
12 |
13 | # This model initially had no columns defined. If you add columns to the
14 | # model remove the '{}' from the fixture names and add the columns immediately
15 | # below each fixture, per the syntax in the comments below
16 | #
17 | one: {}
18 | # column: value
19 | #
20 | two: {}
21 | # column: value
22 |
--------------------------------------------------------------------------------
/test/fixtures/tutors_for_hires.yml:
--------------------------------------------------------------------------------
1 | # == Schema Information
2 | #
3 | # Table name: tutors_for_hires
4 | #
5 | # id :integer not null, primary key
6 | # user_id :integer not null
7 | # subject_id :integer not null
8 | # num_completed :integer default(0), not null
9 | # rate :integer not null
10 | # description :text not null
11 | # created_at :datetime not null
12 | # updated_at :datetime not null
13 | # first_tier :boolean not null
14 | # second_tier :boolean not null
15 | # third_tier :boolean not null
16 | #
17 |
18 | # Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html
19 |
20 | # This model initially had no columns defined. If you add columns to the
21 | # model remove the '{}' from the fixture names and add the columns immediately
22 | # below each fixture, per the syntax in the comments below
23 | #
24 | one: {}
25 | # column: value
26 | #
27 | two: {}
28 | # column: value
29 |
--------------------------------------------------------------------------------
/test/fixtures/users.yml:
--------------------------------------------------------------------------------
1 | # == Schema Information
2 | #
3 | # Table name: users
4 | #
5 | # id :integer not null, primary key
6 | # email :string not null
7 | # zipcode :string not null
8 | # password_digest :string not null
9 | # phone_num :string not null
10 | # session_token :string not null
11 | # created_at :datetime not null
12 | # updated_at :datetime not null
13 | # fname :string not null
14 | # lname :string not null
15 | # image_file_name :string
16 | # image_content_type :string
17 | # image_file_size :integer
18 | # image_updated_at :datetime
19 | #
20 |
21 | # Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html
22 |
23 | one:
24 | name: MyString
25 | email: MyString
26 | zipcode: MyString
27 | password_digest: MyString
28 | phone_num: MyString
29 | session_token: MyString
30 |
31 | two:
32 | name: MyString
33 | email: MyString
34 | zipcode: MyString
35 | password_digest: MyString
36 | phone_num: MyString
37 | session_token: MyString
38 |
--------------------------------------------------------------------------------
/test/helpers/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/victorwu3/Taskable/06e826e3edd0982683390a5bf3ce7f36bc7d8a9f/test/helpers/.keep
--------------------------------------------------------------------------------
/test/integration/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/victorwu3/Taskable/06e826e3edd0982683390a5bf3ce7f36bc7d8a9f/test/integration/.keep
--------------------------------------------------------------------------------
/test/mailers/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/victorwu3/Taskable/06e826e3edd0982683390a5bf3ce7f36bc7d8a9f/test/mailers/.keep
--------------------------------------------------------------------------------
/test/models/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/victorwu3/Taskable/06e826e3edd0982683390a5bf3ce7f36bc7d8a9f/test/models/.keep
--------------------------------------------------------------------------------
/test/models/available_time_test.rb:
--------------------------------------------------------------------------------
1 | # == Schema Information
2 | #
3 | # Table name: available_times
4 | #
5 | # id :integer not null, primary key
6 | # user_id :integer not null
7 | # time_avl :integer not null
8 | # created_at :datetime not null
9 | # updated_at :datetime not null
10 | #
11 |
12 | require 'test_helper'
13 |
14 | class AvailableTimeTest < ActiveSupport::TestCase
15 | # test "the truth" do
16 | # assert true
17 | # end
18 | end
19 |
--------------------------------------------------------------------------------
/test/models/hired_tutor_test.rb:
--------------------------------------------------------------------------------
1 | # == Schema Information
2 | #
3 | # Table name: hired_tutors
4 | #
5 | # id :integer not null, primary key
6 | # user_id :integer not null
7 | # tutor_id :integer not null
8 | # subject_id :integer not null
9 | # rate :integer not null
10 | # description :text not null
11 | # created_at :datetime not null
12 | # updated_at :datetime not null
13 | # date :string
14 | # time_period :string
15 | # location :string
16 | # completed :boolean default(FALSE)
17 | #
18 |
19 | require 'test_helper'
20 |
21 | class HiredTutorTest < ActiveSupport::TestCase
22 | # test "the truth" do
23 | # assert true
24 | # end
25 | end
26 |
--------------------------------------------------------------------------------
/test/models/review_test.rb:
--------------------------------------------------------------------------------
1 | # == Schema Information
2 | #
3 | # Table name: reviews
4 | #
5 | # id :integer not null, primary key
6 | # user_id :integer not null
7 | # body :text not null
8 | # positive :boolean not null
9 | # created_at :datetime not null
10 | # updated_at :datetime not null
11 | # author_id :integer
12 | # subject_id :integer
13 | #
14 |
15 | require 'test_helper'
16 |
17 | class ReviewTest < ActiveSupport::TestCase
18 | # test "the truth" do
19 | # assert true
20 | # end
21 | end
22 |
--------------------------------------------------------------------------------
/test/models/subject_test.rb:
--------------------------------------------------------------------------------
1 | # == Schema Information
2 | #
3 | # Table name: subjects
4 | #
5 | # id :integer not null, primary key
6 | # title :string not null
7 | # created_at :datetime not null
8 | # updated_at :datetime not null
9 | #
10 |
11 | require 'test_helper'
12 |
13 | class SubjectTest < ActiveSupport::TestCase
14 | # test "the truth" do
15 | # assert true
16 | # end
17 | end
18 |
--------------------------------------------------------------------------------
/test/models/time_of_day_test.rb:
--------------------------------------------------------------------------------
1 | # == Schema Information
2 | #
3 | # Table name: time_of_days
4 | #
5 | # id :integer not null, primary key
6 | # time :integer not null
7 | # created_at :datetime not null
8 | # updated_at :datetime not null
9 | #
10 |
11 | require 'test_helper'
12 |
13 | class TimeOfDayTest < ActiveSupport::TestCase
14 | # test "the truth" do
15 | # assert true
16 | # end
17 | end
18 |
--------------------------------------------------------------------------------
/test/models/tutors_for_hire_test.rb:
--------------------------------------------------------------------------------
1 | # == Schema Information
2 | #
3 | # Table name: tutors_for_hires
4 | #
5 | # id :integer not null, primary key
6 | # user_id :integer not null
7 | # subject_id :integer not null
8 | # num_completed :integer default(0), not null
9 | # rate :integer not null
10 | # description :text not null
11 | # created_at :datetime not null
12 | # updated_at :datetime not null
13 | # first_tier :boolean not null
14 | # second_tier :boolean not null
15 | # third_tier :boolean not null
16 | #
17 |
18 | require 'test_helper'
19 |
20 | class TutorsForHireTest < ActiveSupport::TestCase
21 | # test "the truth" do
22 | # assert true
23 | # end
24 | end
25 |
--------------------------------------------------------------------------------
/test/models/user_test.rb:
--------------------------------------------------------------------------------
1 | # == Schema Information
2 | #
3 | # Table name: users
4 | #
5 | # id :integer not null, primary key
6 | # email :string not null
7 | # zipcode :string not null
8 | # password_digest :string not null
9 | # phone_num :string not null
10 | # session_token :string not null
11 | # created_at :datetime not null
12 | # updated_at :datetime not null
13 | # fname :string not null
14 | # lname :string not null
15 | # image_file_name :string
16 | # image_content_type :string
17 | # image_file_size :integer
18 | # image_updated_at :datetime
19 | #
20 |
21 | require 'test_helper'
22 |
23 | class UserTest < ActiveSupport::TestCase
24 | # test "the truth" do
25 | # assert true
26 | # end
27 | end
28 |
--------------------------------------------------------------------------------
/test/system/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/victorwu3/Taskable/06e826e3edd0982683390a5bf3ce7f36bc7d8a9f/test/system/.keep
--------------------------------------------------------------------------------
/test/test_helper.rb:
--------------------------------------------------------------------------------
1 | require File.expand_path('../../config/environment', __FILE__)
2 | require 'rails/test_help'
3 |
4 | class ActiveSupport::TestCase
5 | # Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order.
6 | fixtures :all
7 |
8 | # Add more helper methods to be used by all tests here...
9 | end
10 |
--------------------------------------------------------------------------------
/vendor/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/victorwu3/Taskable/06e826e3edd0982683390a5bf3ce7f36bc7d8a9f/vendor/.keep
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | var path = require('path');
2 | var webpack = require("webpack");
3 |
4 | var plugins = []; // if using any plugins for both dev and production
5 | var devPlugins = []; // if using any plugins for development
6 |
7 | var prodPlugins = [
8 | new webpack.DefinePlugin({
9 | 'process.env': {
10 | 'NODE_ENV': JSON.stringify('production')
11 | }
12 | }),
13 | new webpack.optimize.UglifyJsPlugin({
14 | compress: {
15 | warnings: true
16 | }
17 | })
18 | ];
19 |
20 | plugins = plugins.concat(
21 | process.env.NODE_ENV === 'production' ? prodPlugins : devPlugins
22 | );
23 |
24 |
25 | module.exports = {
26 | entry: './frontend/taskable.jsx',
27 | output: {
28 | filename: './app/assets/javascripts/bundle.js',
29 | },
30 | plugins: plugins,
31 | module: {
32 | loaders: [
33 | {
34 | test: [/\.jsx?$/],
35 | exclude: /(node_modules)/,
36 | loader: 'babel-loader',
37 | query: {
38 | presets: ['env', 'react']
39 | }
40 | }
41 | ]
42 | },
43 | devtool: 'source-map',
44 | resolve: {
45 | extensions: ['.js', '.jsx', '*']
46 | }
47 | };
48 |
--------------------------------------------------------------------------------
/wireframe/homepage:signup.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/victorwu3/Taskable/06e826e3edd0982683390a5bf3ce7f36bc7d8a9f/wireframe/homepage:signup.png
--------------------------------------------------------------------------------
/wireframe/login:taskform.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/victorwu3/Taskable/06e826e3edd0982683390a5bf3ce7f36bc7d8a9f/wireframe/login:taskform.png
--------------------------------------------------------------------------------
/wireframe/taskshow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/victorwu3/Taskable/06e826e3edd0982683390a5bf3ce7f36bc7d8a9f/wireframe/taskshow.png
--------------------------------------------------------------------------------