├── .gitignore
├── Gemfile
├── Gemfile.lock
├── README.md
├── Rakefile
├── app
├── assets
│ ├── config
│ │ └── manifest.js
│ ├── images
│ │ ├── .keep
│ │ ├── attendance.png
│ │ ├── banner_image.jpg
│ │ ├── bed.jpg
│ │ ├── chairs.jpg
│ │ ├── cleaning.jpg
│ │ ├── couch-w-pillow.jpg
│ │ ├── default_avatar.jpg
│ │ ├── favicon.ico
│ │ ├── final_taskrabbit_logo.svg
│ │ ├── hard_drive.jpg
│ │ ├── home_improvements.jpg
│ │ ├── logo.png
│ │ ├── modal-background.jpg
│ │ ├── ordering.jpg
│ │ ├── printing.jpg
│ │ ├── profile_pictures
│ │ │ ├── regular_users
│ │ │ │ ├── prof_pic1.jpg
│ │ │ │ ├── prof_pic2.jpeg
│ │ │ │ ├── prof_pic3.jpg
│ │ │ │ ├── prof_pic4.png
│ │ │ │ └── prof_pic5.jpg
│ │ │ └── taskers
│ │ │ │ ├── tasker1.jpg
│ │ │ │ ├── tasker2.jpg
│ │ │ │ ├── tasker3.png
│ │ │ │ ├── tasker4.jpg
│ │ │ │ ├── tasker5.jpg
│ │ │ │ ├── tasker_prof1.jpg
│ │ │ │ ├── tasker_prof2.jpeg
│ │ │ │ ├── tasker_prof3.jpeg
│ │ │ │ └── tasker_prof4.jpeg
│ │ ├── repairs.jpg
│ │ ├── teaching_assistant.jpg
│ │ ├── trust_badge.svg
│ │ └── tv.jpg
│ ├── javascripts
│ │ ├── application.js
│ │ ├── cable.js
│ │ ├── channels
│ │ │ └── .keep
│ │ └── parseDate.js
│ └── stylesheets
│ │ ├── account.scss
│ │ ├── angel-list-icon.png
│ │ ├── app.scss
│ │ ├── application.css
│ │ ├── banner2.jpg
│ │ ├── base
│ │ ├── AvantGarde.OTF
│ │ ├── MyriadPro-It.ttf
│ │ ├── avante_garde.ttf
│ │ ├── fonts.scss
│ │ ├── icomoon.eot
│ │ ├── icomoon.svg
│ │ ├── icomoon.ttf
│ │ ├── icomoon.woff
│ │ ├── proximanova-bold-webfont.ttf
│ │ ├── proximanova-light-webfont.ttf
│ │ ├── proximanova-regular-webfont.ttf
│ │ ├── proximanova-semibold-webfont.ttf
│ │ └── proximanovat-thin-webfont.ttf
│ │ ├── book.css
│ │ ├── classrabbit.png
│ │ ├── dashboard.css
│ │ ├── footer.scss
│ │ ├── github-icon-final.png
│ │ ├── linkedin-icon-final.png
│ │ ├── login.scss
│ │ ├── microcitybutton.png
│ │ ├── microcitybutton2.png
│ │ ├── new_task.css
│ │ ├── plainChessButton.png
│ │ ├── search.css
│ │ ├── splashLink_photo_med.jpg
│ │ ├── splash_background.png
│ │ ├── splash_background_blur.png
│ │ ├── splash_page.scss
│ │ ├── stage2.css
│ │ ├── tasker_filter.css
│ │ └── taskers.css
├── channels
│ └── application_cable
│ │ ├── channel.rb
│ │ └── connection.rb
├── controllers
│ ├── api
│ │ ├── categories_controller.rb
│ │ ├── sessions_controller.rb
│ │ ├── tasks_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
│ ├── availability.rb
│ ├── category.rb
│ ├── concerns
│ │ └── .keep
│ ├── region.rb
│ ├── skill.rb
│ ├── task.rb
│ └── user.rb
└── views
│ ├── api
│ ├── categories
│ │ └── index.json.jbuilder
│ ├── tasks
│ │ └── index.json.jbuilder
│ └── users
│ │ ├── _user.json.jbuilder
│ │ ├── errors.json.jbuilder
│ │ ├── show.json.jbuilder
│ │ └── taskers.json.jbuilder
│ ├── layouts
│ ├── application.html.erb
│ ├── mailer.html.erb
│ └── mailer.text.erb
│ ├── static_pages
│ └── root.html.erb
│ └── static_templates
│ ├── index.css
│ ├── index.html
│ └── login.html
├── bin
├── bundle
├── rails
├── rake
├── setup
├── spring
└── update
├── 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
│ ├── new_framework_defaults.rb
│ ├── session_store.rb
│ └── wrap_parameters.rb
├── locales
│ └── en.yml
├── puma.rb
├── routes.rb
├── secrets.yml
└── spring.rb
├── db
├── migrate
│ ├── 20170418153334_create_users.rb
│ ├── 20170419223312_add_attachment_avatar_to_users.rb
│ ├── 20170420155039_change_user_phone_number.rb
│ ├── 20170420155907_create_categories.rb
│ ├── 20170420160450_add_attachment_image_to_categories.rb
│ ├── 20170421175638_create_tasks.rb
│ ├── 20170423021306_create_availabilities.rb
│ ├── 20170423025713_add_uniqueness_to_availabilities.rb
│ ├── 20170423030011_complete_uniqueness_to_availabilities.rb
│ ├── 20170423031624_create_skills.rb
│ ├── 20170423041552_remove_phone_numbers_from_skills.rb
│ └── 20170423043602_create_regions.rb
├── schema.rb
└── seeds.rb
├── docs
├── README.md
├── api-endpoints.md
├── component-hierarchy.md
├── sample-state.md
├── schema.md
└── wireframes
│ ├── categorySearch.png
│ ├── favCategoryIndex.png
│ ├── log_in.png
│ ├── newTask.png
│ ├── phase1.png
│ ├── phase2.png
│ ├── phase3.png
│ ├── sign_up.png
│ └── taskIndex.png
├── frontend
├── actions
│ ├── category_actions.js
│ ├── filter_actions.js
│ ├── search_actions.js
│ ├── session_actions.js
│ ├── stage_actions.js
│ ├── task_actions.js
│ └── user_actions.js
├── components
│ ├── account
│ │ ├── account.jsx
│ │ ├── account_container.js
│ │ └── panel
│ │ │ ├── panel.jsx
│ │ │ └── panel_container.js
│ ├── app.jsx
│ ├── dashboard
│ │ ├── dashboard.jsx
│ │ ├── dashboard_container.js
│ │ ├── requested_task.jsx
│ │ ├── requested_tasks.jsx
│ │ ├── requested_tasks_container.js
│ │ ├── task_details.jsx
│ │ └── text.jsx
│ ├── forms
│ │ ├── newTask
│ │ │ ├── new_task.jsx
│ │ │ ├── new_task_container.js
│ │ │ ├── session_util.js
│ │ │ ├── stage1
│ │ │ │ ├── stage1.jsx
│ │ │ │ ├── stage1_container.js
│ │ │ │ ├── taskDescription
│ │ │ │ │ ├── task_description.jsx
│ │ │ │ │ └── task_description_container.js
│ │ │ │ └── taskLocation
│ │ │ │ │ ├── google_autocomplete.js
│ │ │ │ │ ├── location.jsx
│ │ │ │ │ ├── locationDisplay
│ │ │ │ │ ├── location_display.jsx
│ │ │ │ │ └── location_display_container.js
│ │ │ │ │ ├── locationForm
│ │ │ │ │ ├── location_form.jsx
│ │ │ │ │ └── location_form_container.js
│ │ │ │ │ └── location_container.js
│ │ │ ├── stage2
│ │ │ │ ├── Stage2.jsx
│ │ │ │ ├── filter
│ │ │ │ │ ├── Date
│ │ │ │ │ │ ├── date_availability.jsx
│ │ │ │ │ │ ├── date_carousel.jsx
│ │ │ │ │ │ └── date_container.js
│ │ │ │ │ ├── Time
│ │ │ │ │ │ ├── time.jsx
│ │ │ │ │ │ └── time_container.js
│ │ │ │ │ ├── filter.jsx
│ │ │ │ │ ├── filter_container.js
│ │ │ │ │ └── sorted_by.jsx
│ │ │ │ ├── stage2_container.js
│ │ │ │ └── taskers
│ │ │ │ │ ├── tasker.jsx
│ │ │ │ │ ├── taskerIdx.jsx
│ │ │ │ │ ├── taskerIdx_container.js
│ │ │ │ │ └── tasker_container.js
│ │ │ └── stage3
│ │ │ │ ├── confirm.jsx
│ │ │ │ ├── confirm_container.js
│ │ │ │ ├── stage3.jsx
│ │ │ │ ├── stage3_container.js
│ │ │ │ └── task_recap.jsx
│ │ └── sessions
│ │ │ ├── account_details.jsx
│ │ │ ├── edit.jsx
│ │ │ ├── edit_container.js
│ │ │ ├── edit_form.jsx
│ │ │ ├── edit_form_container.js
│ │ │ ├── session_form.jsx
│ │ │ ├── session_form_container.js
│ │ │ └── signup.jsx
│ ├── helpers
│ │ └── icon_helper.jsx
│ ├── nav
│ │ ├── bottom_nav.js
│ │ ├── nav.jsx
│ │ └── nav_container.js
│ ├── root.jsx
│ ├── search
│ │ ├── search.jsx
│ │ └── search_container.js
│ └── splashPage
│ │ ├── splash_page.jsx
│ │ └── splash_page_container.js
├── index.jsx
├── reducers
│ ├── availability_reducer.js
│ ├── category_reducer.js
│ ├── filter_reducer.js
│ ├── new_task_reducer.js
│ ├── root_reducer.js
│ ├── search_reducer.js
│ ├── selectors.js
│ ├── session_reducer.js
│ ├── stage_reducer.js
│ ├── task_reducer.js
│ └── tasker_reducer.js
├── store
│ └── store.js
└── util
│ ├── api_util.js
│ ├── date_util.js
│ ├── form_util.jsx
│ ├── prop_util.js
│ └── sort_util.js
├── lib
├── assets
│ └── .keep
└── tasks
│ └── .keep
├── log
└── .keep
├── package-lock.json
├── package.json
├── public
├── 404.html
├── 422.html
├── 500.html
├── apple-touch-icon-precomposed.png
├── apple-touch-icon.png
├── assets
│ ├── .sprockets-manifest-54a022ed0ef0383c05ebbb51d2791b17.json
│ ├── angel-list-icon-f69a49b38b337b46376ab9071b3812638e935ccc77e4d42bfe60bcd0ff5bb97c.png
│ ├── application-1329aa1b43f69eece5a3c1fe510776e0821aa21ec5303792db2b9c2f0d9e5ea7.js
│ ├── application-1329aa1b43f69eece5a3c1fe510776e0821aa21ec5303792db2b9c2f0d9e5ea7.js.gz
│ ├── application-16f9b15f3ce2510638f0c043c1701a3245e1d27c9a05c7e5f7c79013aabd227d.js
│ ├── application-16f9b15f3ce2510638f0c043c1701a3245e1d27c9a05c7e5f7c79013aabd227d.js.gz
│ ├── application-266a45f600ac94e48316b656ae7da095393f0676c5c9e9a7be88575a83a22f40.css
│ ├── application-266a45f600ac94e48316b656ae7da095393f0676c5c9e9a7be88575a83a22f40.css.gz
│ ├── application-5dc56f91dd3926dab5b27e876ec2b67cad9856d26e0052afdf554f0087823ff5.css
│ ├── application-5dc56f91dd3926dab5b27e876ec2b67cad9856d26e0052afdf554f0087823ff5.css.gz
│ ├── application-6c8096a5b2ef6ba164ba554b26c3d5fbe751cdc001476a2ecc55379293d71864.css
│ ├── application-6c8096a5b2ef6ba164ba554b26c3d5fbe751cdc001476a2ecc55379293d71864.css.gz
│ ├── application-adc8e30501b0ec675ce978cf204a9a228cfcf614c42c86c13b79dd53abf4aa10.css
│ ├── application-adc8e30501b0ec675ce978cf204a9a228cfcf614c42c86c13b79dd53abf4aa10.css.gz
│ ├── application-bf47448ae0701152f71c0c545e09e24d5cdb478e162f373f54b50f9e1c635bc2.js
│ ├── application-bf47448ae0701152f71c0c545e09e24d5cdb478e162f373f54b50f9e1c635bc2.js.gz
│ ├── application-c415be9a01beacaf38e2d3ed8c34fb541b3bfcbdb042cd8248873155abafcd41.js
│ ├── application-c415be9a01beacaf38e2d3ed8c34fb541b3bfcbdb042cd8248873155abafcd41.js.gz
│ ├── application-cab544a031436f8e3a76eadf850f78c7bd3899f46c28c6a2957413c9eb9f23d9.css
│ ├── application-cab544a031436f8e3a76eadf850f78c7bd3899f46c28c6a2957413c9eb9f23d9.css.gz
│ ├── application-e53c00f0227d0e650e45bb21545b1e7aa10af1cfbaac393f451775fc551227f7.css
│ ├── application-e53c00f0227d0e650e45bb21545b1e7aa10af1cfbaac393f451775fc551227f7.css.gz
│ ├── attendance-c21630bb325ed3f45edd939078c1a5a5a63b67b3c59d19ae286aeadd9525cf3f.png
│ ├── banner2-b87d22d18c76e2f251a09a63948893c28e7ba2a150728e5e81603ed65b56dda6.jpg
│ ├── banner_image-040749868f0f75320378b4769bf5d56fe9fc534ff5f9bba3015962cd3eaa8e79.jpg
│ ├── base
│ │ ├── AvantGarde-a5e320e753bf733344275c365255c08179c514c481f04a9f0619b14b4a80efc1.OTF
│ │ ├── MyriadPro-It-ebce431f261a90c864e2ddeb5b40aafc622c88e2b0c0129aa6176fd1268d746b.ttf
│ │ ├── MyriadPro-It-ebce431f261a90c864e2ddeb5b40aafc622c88e2b0c0129aa6176fd1268d746b.ttf.gz
│ │ ├── avante_garde-f75b82705f752a4cbf64b87f458934ed4226f9999831e0d136a4ca48f6bac6c1.ttf
│ │ ├── avante_garde-f75b82705f752a4cbf64b87f458934ed4226f9999831e0d136a4ca48f6bac6c1.ttf.gz
│ │ ├── icomoon-0cf379d83f5f127519328d04b584947f01001cb0111bad35140b302cefa21bb1.woff
│ │ ├── icomoon-2d1273d2da2895aa086b0c1d3fede2b18ed238d5b66d63bf52f0374512c45374.ttf
│ │ ├── icomoon-2d1273d2da2895aa086b0c1d3fede2b18ed238d5b66d63bf52f0374512c45374.ttf.gz
│ │ ├── icomoon-92b12277f104fae86dae18d94337a36d6fe92f33bb5780bfb12a39b4c2a73a87.eot
│ │ ├── icomoon-92b12277f104fae86dae18d94337a36d6fe92f33bb5780bfb12a39b4c2a73a87.eot.gz
│ │ ├── icomoon-b39188588dd12118ac755d6a22769ead6db0d28f704bd9618819ccb513dc5e69.svg
│ │ ├── icomoon-b39188588dd12118ac755d6a22769ead6db0d28f704bd9618819ccb513dc5e69.svg.gz
│ │ ├── proximanova-bold-webfont-a52d304a62b0e194a962f07be15426e76ed9be8e8a6bec3108242946fd96e8a0.ttf
│ │ ├── proximanova-bold-webfont-a52d304a62b0e194a962f07be15426e76ed9be8e8a6bec3108242946fd96e8a0.ttf.gz
│ │ ├── proximanova-light-webfont-70512d9977a8fcd4ba7c77417fb4984984197ca2857ef30206fbfe9dbec96965.ttf
│ │ ├── proximanova-light-webfont-70512d9977a8fcd4ba7c77417fb4984984197ca2857ef30206fbfe9dbec96965.ttf.gz
│ │ ├── proximanova-regular-webfont-2d77cd2df52cebe3d1eb8711a9ab9d0418fecdb343d3841cf9d4fee21e64e9b1.ttf
│ │ ├── proximanova-regular-webfont-2d77cd2df52cebe3d1eb8711a9ab9d0418fecdb343d3841cf9d4fee21e64e9b1.ttf.gz
│ │ ├── proximanova-semibold-webfont-d1f6f72f93791752f7deb94af920ef75b1759b46dd53c9d3b9a4b837d18ad835.ttf
│ │ ├── proximanova-semibold-webfont-d1f6f72f93791752f7deb94af920ef75b1759b46dd53c9d3b9a4b837d18ad835.ttf.gz
│ │ ├── proximanovat-thin-webfont-e637d92c95e7afe0c243b9c00b83c1e64b7743fd9eb0657379a593b9ab7cdeb4.ttf
│ │ └── proximanovat-thin-webfont-e637d92c95e7afe0c243b9c00b83c1e64b7743fd9eb0657379a593b9ab7cdeb4.ttf.gz
│ ├── bed-25362534282e9e8196e8469af71aaea209251f38ab36f813dbc788a6b2c5cc09.jpg
│ ├── bundle.js-0597996fd5ea46a4fad87788d1a5ce2f3a7e543a8809ce48a034079baaa2e6a7.map
│ ├── bundle.js-7146421864e18e9980c91c581024fc6df32df6a33606c0cc313d9bb6231d5569.map
│ ├── bundle.js-7a5afd9c3e4c40396f47a9c8dfcc1e7bd60acce3803e56d5e4e612c8a4f65736.map
│ ├── bundle.js-949bc91ffbba968da0c295169c6f975bcd75d7da293780c67f31954f0f79d832.map
│ ├── chairs-c045c090bb79f7d09f616456bc2252eb4dce55752e7ad4d0e4b74a0391a697c2.jpg
│ ├── classrabbit-02ed074774f1bbc382ca34b94d44ebf0e1e752281925a013dfe7791f2b40e037.png
│ ├── cleaning-34a6f89f4f0c2f141151d75205cc757b62a00623e2bc6f8a4f618aaf427fe099.jpg
│ ├── couch-w-pillow-0aee74a126ac3831b7285cf9f223dcbe95147dfe01e8f53ff737cf0b26decbbf.jpg
│ ├── default_avatar-6c22db894f6a1d7a84717f2c80c30210a42cb94da932f661eb0b060d4d8a2f0e.jpg
│ ├── favicon-e17908cc156f99510192d87dfc461b1b9898b6559a47be4741bb17dda26c83a7.ico
│ ├── favicon-e17908cc156f99510192d87dfc461b1b9898b6559a47be4741bb17dda26c83a7.ico.gz
│ ├── final_taskrabbit_logo-a88d820c4047c02c82df84cc7d67948f6ac7d7004f48202250fe3b7efdc3db34.svg
│ ├── final_taskrabbit_logo-a88d820c4047c02c82df84cc7d67948f6ac7d7004f48202250fe3b7efdc3db34.svg.gz
│ ├── github-icon-final-860f6e03a20a87dfdc2778e5c2521e68417f3cd0e2d678676d1d6088a385363d.png
│ ├── hard_drive-90df10939d245f25cd4907ed2dd95f07e17462127f4acfb56424b4ab5cb758bc.jpg
│ ├── home_improvements-8265e8d01dc48cbdfa4a01097be7c746eed5cee5e4434f98f709ceffe287622a.jpg
│ ├── linkedin-icon-final-4b3fe8eaa84961dccfb421d58d0278bd2a6792f23b78fb5a7cefad96e0beda64.png
│ ├── logo-85ee3f8a9adfc9d00a69681f25043cafcd5e44bebb95c80ad7f32f93dd161924.png
│ ├── microcitybutton-664b09a120c3f417e85e2870b2cb5a5368472d6cb09b44ab73c8b2e0b6c09700.png
│ ├── microcitybutton2-b601b2cfa57a66885c293b95d6f65bd1fe9c9832520833b1785a2344e518a38a.png
│ ├── modal-background-0cd6fcda12129ba567a23982a65fa170eaa69feb9cfefb0bbf160ff3e8f77a14.jpg
│ ├── ordering-7c06c727081ee88d0fba8c7e82b72d967b50d3a5bfe13e90ef35020588683238.jpg
│ ├── plainChessButton-51cda93acaa1861495e091c0f9001f653cf9a3479d7dd185df3c435a76ee5d91.png
│ ├── printing-f33ce00cc4dccda010d3c2be118bf2be5545368062598c9b785de6da7e3ada3e.jpg
│ ├── profile_pictures
│ │ ├── default_avatar-6c22db894f6a1d7a84717f2c80c30210a42cb94da932f661eb0b060d4d8a2f0e.jpg
│ │ ├── regular_users
│ │ │ ├── prof_pic1-78462e5e4ed8ff509571d2692a25b2e11c36a97f3fb84c33c26b9fbb27299f16.jpg
│ │ │ ├── prof_pic2-8a569050c53b5505cd1cf810ea73527daf9bc663debeed40457d8d53fe6aa715.jpg
│ │ │ ├── prof_pic3-86caa139989db187440c0198c387ef5ac226d8846757f92d23883990ad92a20e.jpg
│ │ │ ├── prof_pic4-c25fcf22cc141f8a85d686aa37f776896c5c90709d0abac520a9efadd3e5600b.png
│ │ │ └── prof_pic5-d7d13d287a8bc57a0c74721eaad11a95bc6c3dd8a77bc705e615f933a5833811.jpg
│ │ └── taskers
│ │ │ ├── tasker1-21aacd71fa0e89b1e00e1b62ed6fbd75da4092202f08c798aae805b0f7620028.jpg
│ │ │ ├── tasker1-9dbfdf42a5e1f9391e6f1e72c8bb23aada746bbc7db9f084fa5af4888d59623d.jpg
│ │ │ ├── tasker2-52cdf0788e1d5158ae2c6d6285477bd6d2709ff435e09f397d902534d8c98f76.jpg
│ │ │ ├── tasker3-06dcf2bee12a01be02153747190a3436150c12e48e2448d5b8783efff8705c88.png
│ │ │ ├── tasker3-e819c0ab4e71a806bb36cab558e637ffaba395c8ff758651318eb7cd0b520c10.jpg
│ │ │ ├── tasker4-0e3d8796dfb63d0d97eaebbe9fe1297d58111321e49cdb568827ec2586e45fba.jpg
│ │ │ ├── tasker4-4e5cbdb9da9995cfe9c6ca51db084cb627b0c090b1cab71d370f89a56d8e2c23.jpg
│ │ │ ├── tasker5-b094e663e8eae460230953b999525ef23a1fda9350ee410a5822a0f2ae730399.jpg
│ │ │ ├── tasker_prof1-b687255672fc7f94b8462101660bbb4d407f15502e7475a248f5166f80a144a0.jpg
│ │ │ ├── tasker_prof2-ee9047f617fc7868d945c98a94392aab2a1d8f08210a42cd6403421500309129.jpg
│ │ │ ├── tasker_prof3-0889fdd6464b10021aceb289b3d2f6e10554c2367d81f999ff3d1d7367b7108c.jpg
│ │ │ └── tasker_prof4-8b43deb7f6662b9e60939db99feaf52f104d639074f9cae0653c52fe424bc01c.jpg
│ ├── repairs-bfd09b976f6e2583a6a196cec72a4173ec8b896dbb845b1b9675a69566db5ae1.jpg
│ ├── splashLink_photo_med-95370e9768636accf882bd5ef1d3fdb14d1c55c24c18049f5a71858eec078407.jpg
│ ├── splash_background-aca190b62d2f3c58956f06bcdb4e2727930b4b2397958d0bc8a7eed9575a198b.png
│ ├── splash_background_blur-a9a8cb07010fd928b99a2c6e50453a45257edaa7115d4bea89b5da2e8c154e21.png
│ ├── teaching_assistant-37ec433387c63f751acc3c25eeeb1def70090a03e974c42f44eb4079076aee7b.jpg
│ ├── trust_badge-39be339305b1813c6086fba03d2e8897a9b8ee2869233d1cd83f79fa20a2c1b8.svg
│ ├── trust_badge-39be339305b1813c6086fba03d2e8897a9b8ee2869233d1cd83f79fa20a2c1b8.svg.gz
│ └── tv-011cd9df181838237a8db3904ce637460ea36593ca1c4f3218524fa3bf4b4021.jpg
├── favicon.ico
└── robots.txt
├── test
├── controllers
│ └── .keep
├── fixtures
│ ├── .keep
│ ├── files
│ │ └── .keep
│ └── users.yml
├── helpers
│ └── .keep
├── integration
│ └── .keep
├── mailers
│ └── .keep
├── models
│ ├── .keep
│ └── user_test.rb
└── test_helper.rb
├── tmp
└── .keep
├── vendor
└── assets
│ ├── javascripts
│ └── .keep
│ └── stylesheets
│ └── .keep
└── webpack.config.js
/.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 | # Ignore Byebug command history file.
17 | .byebug_history
18 | node_modules/
19 | bundle.js
20 | bundle.js.map
21 | .byebug_history
22 | .DS_Store
23 | npm-debug.log
24 |
25 | # Ignore application configuration
26 | /config/application.yml
27 |
--------------------------------------------------------------------------------
/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 |
8 |
9 | # Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
10 | gem 'rails', '~> 5.0.2'
11 | # Use postgresql as the database for Active Record
12 | gem 'pg', '~> 0.18'
13 | # Use Puma as the app server
14 | gem 'puma', '~> 3.0'
15 | # Use SCSS for stylesheets
16 | gem 'sass-rails', '~> 5.0'
17 | # Use Uglifier as compressor for JavaScript assets
18 | gem 'uglifier', '>= 1.3.0'
19 | # Use CoffeeScript for .coffee assets and views
20 | gem 'coffee-rails', '~> 4.2'
21 | # See https://github.com/rails/execjs#readme for more supported runtimes
22 | # gem 'therubyracer', platforms: :ruby
23 | gem 'bcrypt'
24 | # Use jquery as the JavaScript library
25 | gem 'jquery-rails'
26 | # Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder
27 | gem 'jbuilder', '~> 2.5'
28 | gem 'textbelt'
29 |
30 | # Use Redis adapter to run Action Cable in production
31 | # gem 'redis', '~> 3.0'
32 | # Use ActiveModel has_secure_password
33 | # gem 'bcrypt', '~> 3.1.7'
34 | gem "paperclip", "~> 5.0.0"
35 | gem 'paperclip-compression'
36 | gem "figaro"
37 | gem "aws-sdk", ">= 2.0"
38 |
39 | # Use Capistrano for deployment
40 | # gem 'capistrano-rails', group: :development
41 |
42 | group :development, :test do
43 | # Call 'byebug' anywhere in the code to stop execution and get a debugger console
44 | gem 'byebug', platform: :mri
45 | gem 'better_errors'
46 | gem 'binding_of_caller'
47 | gem 'pry-rails'
48 | gem 'annotate'
49 | gem 'faker'
50 | gem 'paperclip-compression'
51 | end
52 |
53 | group :development do
54 | # Access an IRB console on exception pages or by using <%= console %> anywhere in the code.
55 | gem 'web-console', '>= 3.3.0'
56 | gem 'listen', '~> 3.0.5'
57 | # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring
58 | gem 'spring'
59 | gem 'spring-watcher-listen', '~> 2.0.0'
60 | end
61 |
62 | group :production do
63 | gem 'rails_12factor'
64 | gem 'faker'
65 | gem 'paperclip-compression'
66 | end
67 | # Windows does not include zoneinfo files, so bundle the tzinfo-data gem
68 | gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]
69 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # README
2 |
3 | classRabbit is a task requesting tool for teachers built with React, Rails, & Postgres - inspired by TaskRabbit. Teachers can request support on a variety of operational tasks and are matched with community members who would like to volunteer.
4 |
5 | ## Features
6 |
7 | ### Tasks & Categories
8 |
9 | Users can create a task and search through task categories (ie Printing, Ordering).
10 |
11 | ### Taskers, Regions, & Availabilities
12 |
13 | Taskers are workers who complete user provided tasks.
14 |
15 | Users can view a curated list of taskers that are within proximity to their school. Additionally, they can filter taskers by date and time of day availability, number of reviews, and price.
16 |
17 | ## Future Improvements
18 | * Interface for Tasker Sign Up
19 | * Tasker/User Chat Interface
20 |
--------------------------------------------------------------------------------
/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/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/app/assets/images/.keep
--------------------------------------------------------------------------------
/app/assets/images/attendance.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/app/assets/images/attendance.png
--------------------------------------------------------------------------------
/app/assets/images/banner_image.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/app/assets/images/banner_image.jpg
--------------------------------------------------------------------------------
/app/assets/images/bed.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/app/assets/images/bed.jpg
--------------------------------------------------------------------------------
/app/assets/images/chairs.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/app/assets/images/chairs.jpg
--------------------------------------------------------------------------------
/app/assets/images/cleaning.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/app/assets/images/cleaning.jpg
--------------------------------------------------------------------------------
/app/assets/images/couch-w-pillow.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/app/assets/images/couch-w-pillow.jpg
--------------------------------------------------------------------------------
/app/assets/images/default_avatar.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/app/assets/images/default_avatar.jpg
--------------------------------------------------------------------------------
/app/assets/images/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/app/assets/images/favicon.ico
--------------------------------------------------------------------------------
/app/assets/images/hard_drive.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/app/assets/images/hard_drive.jpg
--------------------------------------------------------------------------------
/app/assets/images/home_improvements.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/app/assets/images/home_improvements.jpg
--------------------------------------------------------------------------------
/app/assets/images/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/app/assets/images/logo.png
--------------------------------------------------------------------------------
/app/assets/images/modal-background.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/app/assets/images/modal-background.jpg
--------------------------------------------------------------------------------
/app/assets/images/ordering.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/app/assets/images/ordering.jpg
--------------------------------------------------------------------------------
/app/assets/images/printing.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/app/assets/images/printing.jpg
--------------------------------------------------------------------------------
/app/assets/images/profile_pictures/regular_users/prof_pic1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/app/assets/images/profile_pictures/regular_users/prof_pic1.jpg
--------------------------------------------------------------------------------
/app/assets/images/profile_pictures/regular_users/prof_pic2.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/app/assets/images/profile_pictures/regular_users/prof_pic2.jpeg
--------------------------------------------------------------------------------
/app/assets/images/profile_pictures/regular_users/prof_pic3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/app/assets/images/profile_pictures/regular_users/prof_pic3.jpg
--------------------------------------------------------------------------------
/app/assets/images/profile_pictures/regular_users/prof_pic4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/app/assets/images/profile_pictures/regular_users/prof_pic4.png
--------------------------------------------------------------------------------
/app/assets/images/profile_pictures/regular_users/prof_pic5.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/app/assets/images/profile_pictures/regular_users/prof_pic5.jpg
--------------------------------------------------------------------------------
/app/assets/images/profile_pictures/taskers/tasker1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/app/assets/images/profile_pictures/taskers/tasker1.jpg
--------------------------------------------------------------------------------
/app/assets/images/profile_pictures/taskers/tasker2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/app/assets/images/profile_pictures/taskers/tasker2.jpg
--------------------------------------------------------------------------------
/app/assets/images/profile_pictures/taskers/tasker3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/app/assets/images/profile_pictures/taskers/tasker3.png
--------------------------------------------------------------------------------
/app/assets/images/profile_pictures/taskers/tasker4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/app/assets/images/profile_pictures/taskers/tasker4.jpg
--------------------------------------------------------------------------------
/app/assets/images/profile_pictures/taskers/tasker5.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/app/assets/images/profile_pictures/taskers/tasker5.jpg
--------------------------------------------------------------------------------
/app/assets/images/profile_pictures/taskers/tasker_prof1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/app/assets/images/profile_pictures/taskers/tasker_prof1.jpg
--------------------------------------------------------------------------------
/app/assets/images/profile_pictures/taskers/tasker_prof2.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/app/assets/images/profile_pictures/taskers/tasker_prof2.jpeg
--------------------------------------------------------------------------------
/app/assets/images/profile_pictures/taskers/tasker_prof3.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/app/assets/images/profile_pictures/taskers/tasker_prof3.jpeg
--------------------------------------------------------------------------------
/app/assets/images/profile_pictures/taskers/tasker_prof4.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/app/assets/images/profile_pictures/taskers/tasker_prof4.jpeg
--------------------------------------------------------------------------------
/app/assets/images/repairs.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/app/assets/images/repairs.jpg
--------------------------------------------------------------------------------
/app/assets/images/teaching_assistant.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/app/assets/images/teaching_assistant.jpg
--------------------------------------------------------------------------------
/app/assets/images/tv.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/app/assets/images/tv.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, vendor/assets/javascripts,
5 | // or any plugin's 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 jquery
14 | //= require jquery_ujs
15 | //= require_tree .
16 |
--------------------------------------------------------------------------------
/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/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/app/assets/javascripts/channels/.keep
--------------------------------------------------------------------------------
/app/assets/javascripts/parseDate.js:
--------------------------------------------------------------------------------
1 | const dateAbrev = {
2 | 0: 'Jan',
3 | 1: 'Feb',
4 | 2: 'Mar',
5 | 3: 'Apr',
6 | 4: 'May',
7 | 5: 'Jun',
8 | 6: 'Jul',
9 | 7: 'Aug',
10 | 8: 'Sep',
11 | 9: 'Oct',
12 | 10: 'Nov',
13 | 11: 'Dec'
14 | };
15 |
16 | const dayAbrev = {
17 | 0: 'Sun',
18 | 1: 'Sat',
19 | 2: 'Mon',
20 | 3: 'Tue',
21 | 4: 'Wed',
22 | 5: 'Thu',
23 | 6: 'Fri',
24 | 7: 'Sat'
25 | };
26 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/angel-list-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/app/assets/stylesheets/angel-list-icon.png
--------------------------------------------------------------------------------
/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, vendor/assets/stylesheets,
6 | * or any plugin's 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/banner2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/app/assets/stylesheets/banner2.jpg
--------------------------------------------------------------------------------
/app/assets/stylesheets/base/AvantGarde.OTF:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/app/assets/stylesheets/base/AvantGarde.OTF
--------------------------------------------------------------------------------
/app/assets/stylesheets/base/MyriadPro-It.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/app/assets/stylesheets/base/MyriadPro-It.ttf
--------------------------------------------------------------------------------
/app/assets/stylesheets/base/avante_garde.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/app/assets/stylesheets/base/avante_garde.ttf
--------------------------------------------------------------------------------
/app/assets/stylesheets/base/icomoon.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/app/assets/stylesheets/base/icomoon.eot
--------------------------------------------------------------------------------
/app/assets/stylesheets/base/icomoon.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/app/assets/stylesheets/base/icomoon.ttf
--------------------------------------------------------------------------------
/app/assets/stylesheets/base/icomoon.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/app/assets/stylesheets/base/icomoon.woff
--------------------------------------------------------------------------------
/app/assets/stylesheets/base/proximanova-bold-webfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/app/assets/stylesheets/base/proximanova-bold-webfont.ttf
--------------------------------------------------------------------------------
/app/assets/stylesheets/base/proximanova-light-webfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/app/assets/stylesheets/base/proximanova-light-webfont.ttf
--------------------------------------------------------------------------------
/app/assets/stylesheets/base/proximanova-regular-webfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/app/assets/stylesheets/base/proximanova-regular-webfont.ttf
--------------------------------------------------------------------------------
/app/assets/stylesheets/base/proximanova-semibold-webfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/app/assets/stylesheets/base/proximanova-semibold-webfont.ttf
--------------------------------------------------------------------------------
/app/assets/stylesheets/base/proximanovat-thin-webfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/app/assets/stylesheets/base/proximanovat-thin-webfont.ttf
--------------------------------------------------------------------------------
/app/assets/stylesheets/classrabbit.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/app/assets/stylesheets/classrabbit.png
--------------------------------------------------------------------------------
/app/assets/stylesheets/footer.scss:
--------------------------------------------------------------------------------
1 |
2 | footer {
3 |
4 | display: flex;
5 | flex-direction: column;
6 | justify-content: flex-start;
7 | align-items: center;
8 | width: 100%;
9 | background-color: #67727e;
10 | height: 352px;
11 | padding-top: 32px;
12 | }
13 |
14 | footer a, footer p {
15 | font-family: "Proxima-Nova-Thin";
16 | display: block;
17 | color: white;
18 | font-size: 20px;
19 | font-style: normal;
20 | font-weight: normal;
21 | height: 1.5em;
22 | line-height: 1.5em;
23 | list-style-position: outside;
24 | }
25 |
26 | footer span {
27 | font-family: "Proxima-Nova-Thin";
28 | height: 1.5em;
29 | line-height: 1.5em;
30 | }
31 |
32 |
33 | .download-app.desc {
34 | color: white;
35 | margin-bottom: 15px;
36 | }
37 |
38 | .bottom-nav {
39 | display: flex;
40 | justify-content: center;
41 | }
42 |
43 | .bottom-nav > div {
44 | width: 33%;
45 | }
46 |
47 | .social-media div {
48 | height: 24px;
49 | width: 24px;
50 | background-size: contain;
51 | background-repeat: no-repeat;
52 | }
53 |
54 | .linkedin {
55 | background-image: image_url("./linkedin-icon-final.png");
56 | }
57 |
58 | .github {
59 | background-image: image_url("./github-icon-final.png");
60 | }
61 |
62 | .angel-list {
63 | background-image: image_url("./angel-list-icon.png");
64 |
65 | }
66 |
67 | .social-media {
68 | margin-bottom: 10px;
69 | display: flex;
70 | align-items: center;
71 | margin-left: 4px;
72 | }
73 |
74 | .social-media a {
75 | padding: 0px 8px 0px 8px;
76 | }
77 |
78 | .download-app {
79 | display: flex;
80 | flex-direction: column;
81 | align-items: space-between;
82 | }
83 |
84 | .download-app img {
85 | height: 45px;
86 | width: auto;
87 | }
88 |
89 | .app-store-buttons {
90 | display: flex;
91 | justify-content: space-between;
92 | width: 125%;
93 | margin-top: 5px;
94 | }
95 |
96 | .microcity {
97 | height: 100px;
98 | width: 200px;
99 | background-size: contain;
100 | background-repeat: no-repeat;
101 | background-image: image_url("./microcitybutton2.png");
102 | }
103 |
104 | .app-store-buttons a {
105 | margin-left: 15px;
106 | }
107 | .plainchess {
108 |
109 | width: 200px;
110 | margin-top: 6px;
111 | height: 60px;
112 | background-size: contain;
113 | background-repeat: no-repeat;
114 | background-image: image_url("./plainChessButton.png");
115 | }
116 | footer span {
117 | color: #b1b9c3;
118 | font-size: 20px;
119 | font-style: normal;
120 | font-weight: 300;
121 | height: auto;
122 | line-height: 30px;
123 | }
124 |
125 |
126 | footer > section {
127 | width: 65%;
128 | }
129 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/github-icon-final.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/app/assets/stylesheets/github-icon-final.png
--------------------------------------------------------------------------------
/app/assets/stylesheets/linkedin-icon-final.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/app/assets/stylesheets/linkedin-icon-final.png
--------------------------------------------------------------------------------
/app/assets/stylesheets/microcitybutton.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/app/assets/stylesheets/microcitybutton.png
--------------------------------------------------------------------------------
/app/assets/stylesheets/microcitybutton2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/app/assets/stylesheets/microcitybutton2.png
--------------------------------------------------------------------------------
/app/assets/stylesheets/plainChessButton.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/app/assets/stylesheets/plainChessButton.png
--------------------------------------------------------------------------------
/app/assets/stylesheets/search.css:
--------------------------------------------------------------------------------
1 | .search-container {
2 | position: relative;
3 | }
4 |
5 | .search-result.category.hidden {
6 | display: none;
7 | }
8 |
9 | .search-results-container {
10 | display: flex;
11 | position: absolute;
12 | z-index: 500;
13 | flex-direction: column;
14 | width: 100%;
15 | /*border: 0.25px solid #dce0e6;*/
16 | /*box-shadow */
17 | }
18 |
19 | .search-result {
20 | height: 75px;
21 | position: relative;
22 | background-color: white;
23 | display: flex;
24 | align-items: center;
25 | justify-content: flex-start;
26 | color: rgb(81, 175, 51);
27 | }
28 |
29 | .search-result:hover {
30 | background-color: rgba(245, 245, 245, 0.98);
31 | cursor: pointer;
32 | }
33 |
34 |
35 | #search-bar {
36 | margin-top: 15px;
37 | height: auto;
38 | width:100%;
39 | display: flex;
40 | flex-direction: row;
41 | align-items: center;
42 | border: 1px solid #dce0e6;
43 | border-radius: 4px;
44 | background-color: white;
45 | }
46 |
47 | .icon-search {
48 | color: rgb(81, 175, 51);
49 | }
50 | .icon-cancel-circle {
51 |
52 | }
53 |
54 | .icon-cancel-circle:hover {
55 | cursor: pointer;
56 | color: red;
57 | }
58 |
59 | .icon-x-altx-alt {
60 | color: rgb(135, 140, 146);
61 | }
62 |
63 | .icon-x-altx-alt:hover {
64 | cursor: pointer;
65 |
66 | }
67 | .search-cat {
68 | border-radius: 50%;
69 | margin-left: 25px;
70 | margin-right: 25px;
71 | height: 60px;
72 | width: auto;
73 | }
74 |
75 | #search-bar i {
76 | background-color: white;
77 | margin-left: 10px;
78 | margin-right: 10px;
79 | }
80 |
81 | #search-bar input[type=text]:focus,
82 | .search-bar.input {
83 | flex: 1;
84 | padding: 10px 0px;
85 | /*padding-right: 0px;*/
86 | height: 24px;
87 | font-size: 1em;
88 | font-family: "Proxima-Nova-Light";
89 | padding-left: 2.5em;
90 | z-index: 50;
91 | border: 0px;
92 | vertical-align: middle;
93 | border-radius: 0px;
94 | text-rendering: auto;
95 | color: initial;
96 | letter-spacing: normal;
97 | word-spacing: normal;
98 | text-transform: none;
99 | text-indent: 0px;
100 | text-shadow: none;
101 | text-align: start;
102 | margin-top: 0px;
103 | line-height: 24px;
104 | -webkit-appearance: textfield;
105 | background-color: white;
106 | -webkit-rtl-ordering: logical;
107 | user-select: text;
108 | cursor: auto;
109 | width: 80%;
110 | }
111 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/splashLink_photo_med.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/app/assets/stylesheets/splashLink_photo_med.jpg
--------------------------------------------------------------------------------
/app/assets/stylesheets/splash_background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/app/assets/stylesheets/splash_background.png
--------------------------------------------------------------------------------
/app/assets/stylesheets/splash_background_blur.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/app/assets/stylesheets/splash_background_blur.png
--------------------------------------------------------------------------------
/app/assets/stylesheets/splash_page.scss:
--------------------------------------------------------------------------------
1 | .splashContainer {
2 | width: 100%;
3 | min-height: 800px;
4 | background-color: white;
5 | }
6 |
7 | .splashBanner {
8 | width: 100%;
9 | min-height: 600px;
10 | background-image: image_url("./splash_background_blur.png");
11 | background-size: cover;
12 | background-repeat: no-repeat;
13 | display: flex;
14 | justify-content: center;
15 | align-items: center;
16 | margin-bottom: 3em;
17 | }
18 |
19 | .splashBox {
20 | background-color: white;
21 | width: 500px;
22 | height: 300px;
23 | display: flex;
24 | flex-direction: column;
25 | align-items: center;
26 | padding: 3.5rem;
27 |
28 | }
29 |
30 | .splashBox_title {
31 | line-height: 1.2;
32 | font-size: 2.5rem;
33 | font-family: "Proxima-Nova-Light";
34 | }
35 |
36 | .splashBox_spacer {
37 | border-bottom: 1px solid rgb(81, 175, 51);
38 | height: 0px;
39 | width: 50px;
40 | margin: 32px 0px;
41 | }
42 |
43 | .splashBox_subtitle {
44 | padding: 20px 0px;
45 | width: 100%;
46 | text-align: center;
47 | display: flex;
48 | justify-content: center;
49 | font-family: "Proxima-Nova-Thin";
50 | font-size: 1.5rem;
51 | line-height: 36px;
52 | }
53 | .splashBox_search {
54 |
55 | width: 100%;
56 | }
57 |
58 | .splashBox_search.search-container {
59 | width: 100%;
60 | }
61 |
62 | .splashBox_search input.search-bar.input {
63 | padding: 15px 0px;
64 | }
65 |
66 | .splashLinks_container {
67 | display: flex;
68 | flex-direction: column;
69 | width: 100%;
70 | align-items: center;
71 | background-color: white;
72 | margin-bottom: 80px;
73 | }
74 |
75 | .splashLinks_title {
76 | margin-bottom: 40px;
77 | font-size: 40px;
78 | font-family: "Proxima-Nova-Light"
79 | }
80 |
81 | .splashLinks_row {
82 | display: flex;
83 | flex-direction: row;
84 | justify-content: center;
85 | padding: 0px 16px;
86 | margin: 0px 40px 20px 40px;
87 | }
88 |
89 | .splashLink_content {
90 | font-family: "Proxima-Nova-Light";
91 | padding: 32px;
92 | display: flex;
93 | align-items: center;
94 | justify-content: center;
95 | flex-direction: column;
96 | text-align: center;
97 | font-size: 24px;
98 | flex: .3;
99 | background-color: rgb(249, 250, 251);
100 | }
101 |
102 | .splashLink_content button {
103 | font-size: 16px;
104 | font-family: "Proxima-Nova-Thin";
105 | padding: 10px 28px;
106 | width: 236px;
107 | }
108 |
109 | .splashLink_photo_med {
110 | flex: 1;
111 | background-image: image_url("./splashLink_photo_med.jpg");
112 | background-size: contain;
113 | background-repeat: no-repeat;
114 | height: 390px;
115 | width: 700px;
116 | }
117 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/stage2.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/app/assets/stylesheets/stage2.css
--------------------------------------------------------------------------------
/app/assets/stylesheets/taskers.css:
--------------------------------------------------------------------------------
1 |
2 |
3 | .stage2-container {
4 | display: flex;
5 | flex-direction: row;
6 | justify-content: flex-end;
7 |
8 | }
9 |
10 |
11 | .taskers-index {
12 | flex: 0.8;
13 | min-height: 600px;
14 | }
15 |
16 | .tasker-container {
17 | background: white;
18 | border: 1px solid #dce0e6;
19 | border-radius: 4px;
20 | padding: 2rem;
21 | margin-bottom: 2rem;
22 | display: flex;
23 | flex-direction: row;
24 | justify-content: flex-start;
25 | }
26 |
27 | .profile-aside {
28 | display: inherit;
29 | flex-direction: column;
30 | justify-content: center;
31 | align-items: center;
32 | flex-grow: 2;
33 | flex-shrink: 1;
34 | min-width: 210px;
35 | }
36 |
37 |
38 |
39 | .profile-aside img {
40 |
41 | }
42 |
43 | .tasker-info {
44 | margin-left: 2rem;
45 | display: inherit;
46 | flex-direction: column;
47 | justify-content: center;
48 |
49 | flex-grow: 5;
50 | flex-shrink:1;
51 |
52 | }
53 |
54 | .tasker-quote-container img {
55 | min-width: 72px;
56 | min-height: 72px;
57 |
58 | }
59 |
60 |
61 | .tasker-title h3{
62 | font-size: 2em;
63 | font-family: "Proxima-Nova-Bold";
64 | margin-bottom: 8px;
65 | /*font-weight: bold;*/
66 | }
67 |
68 |
69 | .tasker-title{
70 | margin-bottom: 16px;
71 | }
72 |
73 | .tasker-title p {
74 | line-height: 24px;
75 | font-size: 16px;
76 |
77 | }
78 |
79 | .select-tasker {
80 | margin: 16px 0px;
81 | padding: 10.125px 20.250px;
82 | width: 100%;
83 | }
84 |
85 | .tasker-body {
86 | padding-top: 16px;
87 | border-top: 1px solid rgb(220, 224, 230);
88 | height: 100%;
89 | }
90 |
91 | .tasker-body h6 {
92 | font-size: 1rem;
93 | font-family: "Proxima-Nova-Bold";
94 | line-height: 24px;
95 |
96 | }
97 |
98 | .tasker-quote-container {
99 | margin-top: 18px;
100 | display: flex;
101 | flex-direction: row;
102 |
103 | }
104 |
105 | .tasker-quote {
106 | font-style: italic;
107 | }
108 |
--------------------------------------------------------------------------------
/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/categories_controller.rb:
--------------------------------------------------------------------------------
1 | class Api::CategoriesController < ApplicationController
2 | def index
3 | @categories = Category.all
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/app/controllers/api/sessions_controller.rb:
--------------------------------------------------------------------------------
1 | class Api::SessionsController < ApplicationController
2 |
3 | def create
4 | @user = User.find_by_credentials(user_params[:email], user_params[:password])
5 | if @user
6 | log_in!(@user)
7 | render "api/users/show"
8 | else
9 | render(
10 | json: {:password => "Invalid login"},
11 | status: 401
12 | )
13 | end
14 | end
15 |
16 | def destroy
17 | @user = current_user
18 | if @user
19 | log_out!
20 | render json: {}
21 | else
22 | render(
23 | json: ["Not signed in"],
24 | status: 404
25 | )
26 | end
27 | end
28 |
29 | private
30 |
31 | def user_params
32 | params.require(:user).permit(:email, :password)
33 | end
34 |
35 | end
36 |
--------------------------------------------------------------------------------
/app/controllers/api/tasks_controller.rb:
--------------------------------------------------------------------------------
1 | class Api::TasksController < ApplicationController
2 |
3 | def index
4 | @tasks = current_user.requested_tasks.joins(:category).includes(:tasker)
5 | render 'api/tasks/index'
6 | end
7 |
8 | def create
9 | @task = Task.new(task_params)
10 | @task.requestor_id = current_user.id
11 | if @task.save
12 | redirect_to 'api/tasks/index'
13 | else
14 | render json: @task.errors.messages, status: 422
15 | end
16 | end
17 |
18 | def destroy
19 |
20 | end
21 |
22 |
23 | def update
24 |
25 | end
26 |
27 | private
28 |
29 | def task_params
30 | params.require(:task).permit(:description, :location, :locality, :date, :time, :category_id, :tasker_id)
31 | end
32 | end
33 |
--------------------------------------------------------------------------------
/app/controllers/api/users_controller.rb:
--------------------------------------------------------------------------------
1 | class Api::UsersController < ApplicationController
2 |
3 | def create
4 | locality = user_params[:locality]
5 | if Region.find_by(locality: locality).nil?
6 | Region.create(locality: locality)
7 | end
8 |
9 | @user = User.new(user_params)
10 |
11 | if @user.save
12 | log_in!(@user)
13 | render "api/users/show"
14 | else
15 | render json: @user.errors.messages, status: 422
16 | end
17 | end
18 |
19 | def update
20 | debugger
21 | @user = User.find(params[:id])
22 | if @user.update(user_params)
23 | render "api/users/show"
24 | else
25 | render json: @user.errors.full_messages, status: 422
26 | end
27 | end
28 |
29 | def destroy
30 | @user = User.find(params[:id])
31 | if @user.destroy
32 |
33 | else
34 | render json: @user.errors.full_messages, status: 422
35 | end
36 | end
37 |
38 | def taskers
39 | @category_id = params[:category_id]
40 | @taskers = User.in_region_with_skill(params[:locality], params[:category_id])
41 | @availabilities = User.recent_availabilities(@taskers, Date.today, Date.today + 12)
42 | render "api/users/taskers"
43 | end
44 |
45 | def show
46 | @user = User.find(params[:id])
47 | render "api/users/show"
48 | end
49 |
50 |
51 | private
52 |
53 | def user_params
54 | params.require(:user).permit(:fname, :lname, :email, :password, :zip_code, :locality, :phone_number)
55 | end
56 |
57 | end
58 |
--------------------------------------------------------------------------------
/app/controllers/application_controller.rb:
--------------------------------------------------------------------------------
1 | class ApplicationController < ActionController::Base
2 | protect_from_forgery with: :exception
3 | helper_method :current_user, :logged_in?
4 |
5 | def current_user
6 | user = User.find_by(session_token: session[:session_token])
7 | user ? user : nil
8 | end
9 |
10 | def logged_in?
11 | !current_user.nil?
12 | end
13 |
14 | def log_in!(user)
15 | user.reset_session_token!
16 | session[:session_token] = user.session_token
17 | end
18 |
19 | def log_out!
20 | current_user.reset_session_token!
21 | session[:session_token] = ""
22 | end
23 |
24 | def require_logged_in
25 | render json: {base: ['invalid credentials']}, status: 401 if !current_user
26 | end
27 | end
28 |
--------------------------------------------------------------------------------
/app/controllers/concerns/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/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/availability.rb:
--------------------------------------------------------------------------------
1 | class Availability < ApplicationRecord
2 | validates :tasker_id, :date, :time, presence: true
3 | validates :tasker_id, uniqueness: {scope: [:date, :time]}
4 |
5 |
6 | belongs_to :tasker,
7 | primary_key: :id,
8 | foreign_key: :tasker_id,
9 | class_name: "User"
10 |
11 |
12 | def self.by_date(availabilities)
13 | date_hash = Hash.new {|hash, key| hash[key] = [] }
14 | availabilities.each do |availability|
15 | date_hash[availability.date] = date_hash[availability.date] << availability
16 | end
17 |
18 | date_hash
19 | end
20 | end
21 |
--------------------------------------------------------------------------------
/app/models/category.rb:
--------------------------------------------------------------------------------
1 | class Category < ApplicationRecord
2 | validates :title, :description, presence: true
3 | has_attached_file :image, default_url: "cleaning.jpg", :styles => {
4 | :thumb => "75x75#",
5 | :small => "550x400>",
6 | :medium => "200x200" }
7 |
8 | validates_attachment_content_type :image, content_type: /\Aimage\/.*\Z/
9 |
10 | has_many :tasks,
11 | primary_key: :id,
12 | foreign_key: :category_id,
13 | class_name: "Task"
14 |
15 | has_many :skills,
16 | primary_key: :id,
17 | foreign_key: :category_id,
18 | class_name: "Category"
19 |
20 |
21 | end
22 |
--------------------------------------------------------------------------------
/app/models/concerns/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/app/models/concerns/.keep
--------------------------------------------------------------------------------
/app/models/region.rb:
--------------------------------------------------------------------------------
1 | class Region < ApplicationRecord
2 | validates :locality, presence: true, uniqueness: true
3 |
4 | has_many :taskers,
5 | primary_key: :locality,
6 | foreign_key: :locality,
7 | class_name: "User"
8 |
9 | has_many :tasks,
10 | primary_key: :locality,
11 | foreign_key: :locality,
12 | class_name: "Task"
13 |
14 | end
15 |
--------------------------------------------------------------------------------
/app/models/skill.rb:
--------------------------------------------------------------------------------
1 | class Skill < ApplicationRecord
2 | validates :tasker_id, :category_id, :pitch, :price, :reviews, presence: true
3 | validates_uniqueness_of :tasker_id, :scope => :category_id
4 |
5 | belongs_to :tasker,
6 | primary_key: :id,
7 | foreign_key: :tasker_id,
8 | class_name: "User"
9 |
10 | belongs_to :category,
11 | primary_key: :id,
12 | foreign_key: :category_id,
13 | class_name: "Category"
14 |
15 | belongs_to :quote_author,
16 | primary_key: :id,
17 | foreign_key: :author_id,
18 | class_name: "User"
19 |
20 | end
21 |
--------------------------------------------------------------------------------
/app/models/task.rb:
--------------------------------------------------------------------------------
1 | class Task < ApplicationRecord
2 | validates :description, :locality, :date, :time, :requestor_id, :category_id, :tasker_id, presence: true
3 |
4 | belongs_to :category,
5 | primary_key: :id,
6 | foreign_key: :category_id,
7 | class_name: "Category"
8 |
9 | belongs_to :requestor,
10 | primary_key: :id,
11 | foreign_key: :requestor_id,
12 | class_name: "User"
13 |
14 | belongs_to :tasker,
15 | primary_key: :id,
16 | foreign_key: :tasker_id,
17 | class_name: "User"
18 |
19 | belongs_to :region,
20 | primary_key: :locality,
21 | foreign_key: :locality,
22 | class_name: "Region"
23 |
24 | end
25 |
--------------------------------------------------------------------------------
/app/views/api/categories/index.json.jbuilder:
--------------------------------------------------------------------------------
1 | @categories.each do |category|
2 | json.set! category.id do
3 | json.id category.id
4 | json.title category.title
5 | json.description category.description
6 | json.img_url_search asset_path(category.image.url(:thumb))
7 | json.img_url_fav_cat asset_path(category.image.url(:small))
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/app/views/api/tasks/index.json.jbuilder:
--------------------------------------------------------------------------------
1 | @tasks.each do |task|
2 | json.set! task.id do
3 | json.id task.id
4 | json.title task.category.title
5 | json.tasker_img_url asset_path(task.tasker.avatar.url(:thumb))
6 | json.tasker_id task.tasker_id
7 | json.date task.date
8 | json.time task.time
9 | json.details do
10 | json.location task.location
11 | json.tasker_fname task.tasker.fname
12 | json.tasker_linitial task.tasker.lname[0]
13 | json.description task.description
14 | end
15 | end
16 | end
17 |
--------------------------------------------------------------------------------
/app/views/api/users/_user.json.jbuilder:
--------------------------------------------------------------------------------
1 | json.id user.id
2 | json.email user.email
3 | json.fname user.fname
4 | json.lname user.lname
5 | json.phone_number user.phone_number
6 | json.zip_code user.zip_code
7 | json.img_url asset_path(user.avatar.url(:thumb))
8 | json.img_url_small asset_path(user.avatar.url(:small))
9 | json.img_url_med asset_path(user.avatar.url(:medium))
10 |
--------------------------------------------------------------------------------
/app/views/api/users/errors.json.jbuilder:
--------------------------------------------------------------------------------
1 | json.errors do
2 | @user.errors.messages.keys do |key|
3 | json.set! key, @user.errors.messages.get(key)
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/app/views/api/users/show.json.jbuilder:
--------------------------------------------------------------------------------
1 | json.zip_code @user.zip_code
2 | json.phone_number @user.phone_number
3 | json.email @user.email
4 | json.lname @user.lname
5 | json.fname @user.fname
6 | json.id @user.id
7 | json.img_url asset_path(@user.avatar.url(:thumb))
8 | json.img_url_small asset_path(@user.avatar.url(:small))
9 | json.img_url_med asset_path(@user.avatar.url(:medium))
10 |
--------------------------------------------------------------------------------
/app/views/api/users/taskers.json.jbuilder:
--------------------------------------------------------------------------------
1 | json.taskers do
2 | @taskers.each do |tasker|
3 | json.set! tasker.id do
4 | json.id tasker.id
5 | json.fname tasker.fname
6 | json.lname_initial tasker.lname[0]
7 | json.tasker_avatar_url asset_path(tasker.avatar.url(:medium))
8 | json.price Random.rand(50)
9 | json.task_count tasker.task_count(@category_id)
10 | json.review_count tasker.review_count(@category_id)
11 | json.rating Random.rand(100)
12 | tasker.skills.each do |skill|
13 | json.pitch skill.pitch
14 | json.quote skill.quote
15 | json.author_avatar_url asset_path(skill.quote_author.avatar.url(:small))
16 | end
17 | end
18 | end
19 | end
20 | json.availabilities Availability.by_date(@availabilities)
21 |
22 | if @taskers.length > 0
23 | json.present "true"
24 | else
25 | json.present "false"
26 | end
27 |
--------------------------------------------------------------------------------
/app/views/layouts/application.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | ClassRabbit
5 | <%= csrf_meta_tags %>
6 | <%= stylesheet_link_tag 'application', media: 'all' %>
7 |
8 |
9 | <%= javascript_include_tag 'application' %>
10 |
12 | <%= favicon_link_tag 'favicon.ico' %>
13 |
14 |
15 |
16 | <%= yield %>
17 |
18 |
19 |
--------------------------------------------------------------------------------
/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 |
2 |
3 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/app/views/static_templates/login.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |

12 |
13 |
14 |
15 |
16 |
17 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/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 | # puts "\n== Copying sample files =="
22 | # unless File.exist?('config/database.yml')
23 | # cp 'config/database.yml.sample', 'config/database.yml'
24 | # end
25 |
26 | puts "\n== Preparing database =="
27 | system! 'bin/rails db:setup'
28 |
29 | puts "\n== Removing old logs and tempfiles =="
30 | system! 'bin/rails log:clear tmp:clear'
31 |
32 | puts "\n== Restarting application server =="
33 | system! 'bin/rails restart'
34 | end
35 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 ClassRabbit
10 | class Application < Rails::Application
11 |
12 | config.paperclip_defaults = {
13 | :storage => :s3,
14 | :s3_credentials => {
15 | :bucket => ENV["s3_bucket"],
16 | :access_key_id => ENV["s3_access_key_id"],
17 | :secret_access_key => ENV["s3_secret_access_key"],
18 | :s3_region => ENV["s3_region"]
19 | }
20 | }
21 |
22 |
23 | # Settings in config/environments/* take precedence over those specified here.
24 | # Application configuration should go into files in config/initializers
25 | # -- all .rb files in that directory are automatically loaded.
26 | end
27 | end
28 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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=172800'
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/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=3600'
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 | # ApplicationController.renderer.defaults.merge!(
4 | # http_host: 'example.org',
5 | # https: false
6 | # )
7 |
--------------------------------------------------------------------------------
/config/initializers/assets.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # Version of your assets, change this if you want to expire all your assets.
4 | Rails.application.config.assets.version = '1.0'
5 |
6 | # Add additional assets to the asset load path
7 | # Rails.application.config.assets.paths << Emoji.images_path
8 |
9 | # Precompile additional assets.
10 | # application.js, application.css, and all non-JS/CSS in app/assets folder are already added.
11 | # Rails.application.config.assets.precompile += %w( search.js )
12 |
--------------------------------------------------------------------------------
/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/new_framework_defaults.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 | #
3 | # This file contains migration options to ease your Rails 5.0 upgrade.
4 | #
5 | # Read the Guide for Upgrading Ruby on Rails for more info on each option.
6 |
7 | # Enable per-form CSRF tokens. Previous versions had false.
8 | Rails.application.config.action_controller.per_form_csrf_tokens = true
9 |
10 | # Enable origin-checking CSRF mitigation. Previous versions had false.
11 | Rails.application.config.action_controller.forgery_protection_origin_check = true
12 |
13 | # Make Ruby 2.4 preserve the timezone of the receiver when calling `to_time`.
14 | # Previous versions had false.
15 | ActiveSupport.to_time_preserves_timezone = true
16 |
17 | # Require `belongs_to` associations by default. Previous versions had false.
18 | Rails.application.config.active_record.belongs_to_required_by_default = true
19 |
20 | # Do not halt callback chains when a callback returns false. Previous versions had true.
21 | ActiveSupport.halt_callback_chains_on_return_false = false
22 |
23 | # Configure SSL options to enable HSTS with subdomains. Previous versions had false.
24 | Rails.application.config.ssl_options = { hsts: { subdomains: true } }
25 |
--------------------------------------------------------------------------------
/config/initializers/session_store.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | Rails.application.config.session_store :cookie_store, key: '_classRabbit_session'
4 |
--------------------------------------------------------------------------------
/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 | # To learn more, please read the Rails Internationalization guide
20 | # available at http://guides.rubyonrails.org/i18n.html.
21 |
22 | en:
23 | hello: "Hello world"
24 |
--------------------------------------------------------------------------------
/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 }.to_i
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 | # The code in the `on_worker_boot` will be called if you are using
36 | # clustered mode by specifying a number of `workers`. After each worker
37 | # process is booted this block will be run, if you are using `preload_app!`
38 | # option you will want to use this block to reconnect to any threads
39 | # or connections that may have been created at application boot, Ruby
40 | # cannot share connections between processes.
41 | #
42 | # on_worker_boot do
43 | # ActiveRecord::Base.establish_connection if defined?(ActiveRecord)
44 | # end
45 |
46 | # Allow puma to be restarted by `rails restart` command.
47 | plugin :tmp_restart
48 |
--------------------------------------------------------------------------------
/config/routes.rb:
--------------------------------------------------------------------------------
1 | Rails.application.routes.draw do
2 | root "static_pages#root"
3 |
4 | namespace :api, defaults: {format: :json} do
5 | resources :categories, only: [:index]
6 | resources :tasks, only: [:index, :create, :update, :destroy]
7 | resources :users
8 |
9 | get '/taskers', to: 'users#taskers'
10 | # get '/region/:locality/category/:cid', to: 'users#taskers'
11 | resource :session, only: [:create, :destroy]
12 | end
13 | # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
14 | end
15 |
--------------------------------------------------------------------------------
/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 | development:
14 | secret_key_base: 9b9a1d5c5d1ae947e1ab09c297127375c5b99673de06735966ce4bae00d1b817a2964fe88e89631fc990c0b00593d6e7c9bbe90082017cd231f5733d677790f1
15 |
16 | test:
17 | secret_key_base: 713ed1036e79474baa4888e06db87b38bac255e2ef5e5beb070af154615cada9c6ebf058b4e1ece7c75cb3eb1728a115c5f79c71cded0dcaa8805e9724361bce
18 |
19 | # Do not keep production secrets in the repository,
20 | # instead read values from the environment.
21 | production:
22 | secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
23 |
--------------------------------------------------------------------------------
/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/20170418153334_create_users.rb:
--------------------------------------------------------------------------------
1 | class CreateUsers < ActiveRecord::Migration[5.0]
2 | def change
3 | create_table :users do |t|
4 | t.string :fname, null: false
5 | t.string :lname, null: false
6 | t.string :email, null: false
7 | t.string :password_digest, null: false
8 | t.string :session_token, null: false
9 | t.string :phone_number, null: false
10 | t.string :zip_code, null: false
11 | t.string :locality, null: false
12 | t.boolean :tasker, :default => true, null: false
13 | t.timestamps null: false
14 | end
15 |
16 | add_index :users, :email, unique: true
17 | add_index :users, :locality
18 | end
19 | end
20 |
--------------------------------------------------------------------------------
/db/migrate/20170419223312_add_attachment_avatar_to_users.rb:
--------------------------------------------------------------------------------
1 | class AddAttachmentAvatarToUsers < ActiveRecord::Migration
2 | def self.up
3 | change_table :users do |t|
4 | t.attachment :avatar
5 | end
6 | end
7 |
8 | def self.down
9 | remove_attachment :users, :avatar
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/db/migrate/20170420155039_change_user_phone_number.rb:
--------------------------------------------------------------------------------
1 | class ChangeUserPhoneNumber < ActiveRecord::Migration[5.0]
2 | def change
3 | change_column :users, :phone_number, :string, :default => ""
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/db/migrate/20170420155907_create_categories.rb:
--------------------------------------------------------------------------------
1 | class CreateCategories < ActiveRecord::Migration[5.0]
2 | def change
3 | create_table :categories do |t|
4 | t.string :title, null: false
5 | t.text :description, null: false
6 | end
7 | end
8 | end
9 |
--------------------------------------------------------------------------------
/db/migrate/20170420160450_add_attachment_image_to_categories.rb:
--------------------------------------------------------------------------------
1 | class AddAttachmentImageToCategories < ActiveRecord::Migration
2 | def self.up
3 | change_table :categories do |t|
4 | t.attachment :image
5 | end
6 | end
7 |
8 | def self.down
9 | remove_attachment :categories, :image
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/db/migrate/20170421175638_create_tasks.rb:
--------------------------------------------------------------------------------
1 | class CreateTasks < ActiveRecord::Migration[5.0]
2 | def change
3 | create_table :tasks do |t|
4 | t.text :description, null: false
5 | t.string :location, null: false
6 | t.string :locality, null: false
7 | t.date :date, null: false
8 | t.string :time, null: false
9 | t.integer :requestor_id, null: false
10 | t.integer :category_id, null: false
11 | t.integer :tasker_id, null: false
12 | end
13 |
14 | add_index :tasks, :requestor_id
15 | add_index :tasks, :category_id
16 | add_index :tasks, :tasker_id
17 | end
18 | end
19 |
--------------------------------------------------------------------------------
/db/migrate/20170423021306_create_availabilities.rb:
--------------------------------------------------------------------------------
1 | class CreateAvailabilities < ActiveRecord::Migration[5.0]
2 | def change
3 | create_table :availabilities do |t|
4 | t.integer :tasker_id, null: false
5 | t.date :date, null: false
6 | t.string :time, null: false
7 | end
8 |
9 | add_index :availabilities, :tasker_id
10 | add_index :availabilities, [:date, :time]
11 | end
12 | end
13 |
--------------------------------------------------------------------------------
/db/migrate/20170423025713_add_uniqueness_to_availabilities.rb:
--------------------------------------------------------------------------------
1 | class AddUniquenessToAvailabilities < ActiveRecord::Migration[5.0]
2 | def change
3 | remove_column :availabilities, :date
4 | remove_column :availabilities, :time
5 | end
6 | end
7 |
--------------------------------------------------------------------------------
/db/migrate/20170423030011_complete_uniqueness_to_availabilities.rb:
--------------------------------------------------------------------------------
1 | class CompleteUniquenessToAvailabilities < ActiveRecord::Migration[5.0]
2 | def change
3 | add_column :availabilities, :date, :date
4 | add_column :availabilities, :time, :string
5 | add_index :availabilities, [:tasker_id, :time, :date], unique: true
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/db/migrate/20170423031624_create_skills.rb:
--------------------------------------------------------------------------------
1 | class CreateSkills < ActiveRecord::Migration[5.0]
2 | def change
3 | create_table :skills do |t|
4 | t.integer :tasker_id, null: false
5 | t.integer :category_id, null: false
6 | t.text :pitch, null: false
7 | t.decimal :price, null: false
8 | t.text :reviews, array: true, default: []
9 | t.string :phone_number, null: false
10 | t.text :quote
11 | t.integer :author_id
12 | t.timestamps null: false
13 | end
14 | add_index :skills, :tasker_id
15 | add_index :skills, :category_id
16 | add_index :skills, :author_id
17 | add_index :skills, [:tasker_id, :category_id], unique: true
18 | end
19 | end
20 |
--------------------------------------------------------------------------------
/db/migrate/20170423041552_remove_phone_numbers_from_skills.rb:
--------------------------------------------------------------------------------
1 | class RemovePhoneNumbersFromSkills < ActiveRecord::Migration[5.0]
2 | def change
3 | remove_column :skills, :phone_number
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/db/migrate/20170423043602_create_regions.rb:
--------------------------------------------------------------------------------
1 | class CreateRegions < ActiveRecord::Migration[5.0]
2 | def change
3 | create_table :regions do |t|
4 | t.string :locality
5 | t.timestamps
6 | end
7 | add_index :regions, :locality, unique: true
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/docs/README.md:
--------------------------------------------------------------------------------
1 | # classRabbit
2 |
3 | [Heroku link][heroku]
4 |
5 | [Trello link][trello]
6 |
7 | [heroku]: http://www.herokuapp.com
8 | [trello]: https://trello.com/b/kU1mbDsO/classrabbit
9 |
10 | ## Minimum Viable Product
11 |
12 | classRabbit is a web application inspired by taskRabbit built using Ruby on Rails
13 | and React/Redux. By the end of Week 9, this app will, at a minimum, satisfy the
14 | following criteria with smooth, bug-free navigation, adequate seed data and
15 | sufficient CSS styling:
16 |
17 | - [ ] Hosting on Heroku
18 | - [ ] New account creation, login, and guest/demo login
19 | - [ ] Choose a task & provide task details
20 | - [ ] Filter and select a local tasker
21 | - [ ] Confirm and view bookings
22 | - [ ] Production README [sample](docs/production_readme.md)
23 |
24 | ## Design Docs
25 | * [View Wireframes][wireframes]
26 | * [React Components][components]
27 | * [API endpoints][api-endpoints]
28 | * [DB schema][schema]
29 | * [Sample State][sample-state]
30 |
31 | [wireframes]: docs/wireframes
32 | [components]: docs/component-hierarchy.md
33 | [sample-state]: docs/sample-state.md
34 | [api-endpoints]: docs/api-endpoints.md
35 | [schema]: docs/schema.md
36 |
37 | ## Implementation Timeline
38 |
39 | ### Phase 1: Backend setup and Front End User Authentication (1.5 days)
40 |
41 | **Objective:** Functioning rails project with front-end Authentication
42 |
43 | ### Phase 2: Task & Category Model, API, & Dashboard home page components (1 day)
44 |
45 | **Objective:** User tasks can be viewed and assigned a category via state.
46 |
47 | ### Phase 3: Region Model, API, & newTask/stage1 components (2 days)
48 |
49 | **Objective:** User can create a newTask and provide Location for task via searchBar that autocompletes from Google API nearby places. Potential taskers are selected via API by closest region.
50 |
51 | ### Phase 4: Availability & Skill Model, API, & newTask/stage2 Component (2 days)
52 |
53 | **Objective:** User can view prospective taskers and their skills. User can filter by availability & sort by experience/price.
54 |
55 | ### Phase 5: newTask/stage3 Component (2 days)
56 |
57 | **Objective:** User can review newTask information and complete task booking.
58 |
59 | ### Bonus Features (TBD)
60 | - [ ] View Tasker Profile
61 | - [ ] Fake Payment Processor
62 | - [ ] Become a Tasker
63 |
--------------------------------------------------------------------------------
/docs/api-endpoints.md:
--------------------------------------------------------------------------------
1 | # API Endpoints
2 |
3 | ## HTML API
4 |
5 | ### Root
6 |
7 | - `GET /` - loads React web app
8 |
9 | ## JSON API
10 |
11 | ### Users
12 |
13 | - `POST /api/users`
14 | - `PATCH /api/users`
15 | - `GET /api/user/:id`
16 | - `GET /api/taskers`
17 | - Gets all taskers within region and skill category.
18 |
19 | ### Session
20 |
21 | - `POST /api/session`
22 | - `DELETE /api/session`
23 |
24 | ### Tasks
25 |
26 | - `GET /api/user/:id/tasks`
27 | - Gets all user's tasks
28 | - `POST /api/user/:id/tasks`
29 | - `PATCH /api/user/:id/tasks/:id`
30 | - `DELETE /api/user/:id/tasks/:id`
31 |
32 | ### Skills
33 | - `POST /api/skills`
34 | - For Become a Tasker (if i get there)
35 | - `GET /api/skills`
36 | - For Tasker profile page (if i get there)
37 |
38 | ### Regions
39 | - `POST /api/regions`
40 |
41 | ### Notes/Addtional Info:
42 | - Categories are stored as a vanilla JS object via application.js
43 | - Availabilities/Skills are queried via User model during GET taskers request
44 |
--------------------------------------------------------------------------------
/docs/component-hierarchy.md:
--------------------------------------------------------------------------------
1 | ## Component Hierarchy
2 | ## See additional details here: [Component Details]
3 | [Component Details]: https://docs.google.com/document/d/1I4F-1x01JbSVB8LhdtgmwFTTpvm2qM9c7heQevCTMy0/edit?usp=sharing
4 | **App**
5 | - NavContainer
6 | + Nav
7 | - authFormContainer
8 |
9 | **authFormContainer**
10 | - signUp
11 | - signIn
12 |
13 | **Dashboard**
14 | - searchContainer
15 | - taskIndexContainer
16 | - favCategoryIndex
17 | + favCategory
18 |
19 | **tasksIndexContainer**
20 | - taskIndex
21 | + taskShow
22 | * taskDetail
23 |
24 | **favCategoryIndex**
25 | - favCategory
26 |
27 | **SearchResultsContainer**
28 | - Search
29 | + searchResult
30 |
31 | **newTaskContainer**
32 | - newTask
33 | + stage1Container
34 | + stage2Container
35 | + stage3Container
36 |
37 | **stage1Container**
38 | - stage1
39 | - locationFormContainer
40 | + locationForm
41 | * searchContainer
42 | - taskDescriptionContainer
43 | * taskDescription
44 |
45 | **stage2Container**
46 | - stage2
47 | + taskerFilter
48 | * taskersIndexContainer
49 | * taskersIndex
50 | * taskerShow
51 |
52 | **stage3Container**
53 | - stage3
54 | + bookingInfo
55 | + confirmBooking
56 |
57 | **accountContainer**
58 | - account
59 |
60 | ## Routes
61 |
62 | |Path | Component |
63 | |-------|-------------|
64 | | "/sign-up" | "AuthFormContainer" |
65 | | "/sign-in" | "AuthFormContainer" |
66 | | "/dashboard" | "DashboardContainer" |
67 | | "/dashboard/newTask/" | "newTaskContainer" |
68 | | "/dashboard/newTask/stage1/" | "stage1Container" |
69 | | "/dashboard/newTask/stage2/" | "stage2Container" |
70 | | "/dashboard/newTask/stage3/" | "stage3Container" |
71 | | "/account/:userId" | "accountContainer" |
72 |
--------------------------------------------------------------------------------
/docs/sample-state.md:
--------------------------------------------------------------------------------
1 | ```js
2 | {
3 | currentUser: {
4 | id: 1,
5 | fname: "Danny",
6 | img_url: "/assets/1.png"
7 | },
8 |
9 | auth: {
10 | signUp: {errors: []},
11 | logIn: {errors: []}
12 | },
13 |
14 | tasks: [
15 | {id: 3,
16 | category_id: 4,
17 | tasker_id: 1,
18 | img_url: "/assets/2.png", // tasker img_url
19 | date: "03212017",
20 | time: "morning"
21 | details: { hidden: true // prop describing if task details are revealed
22 | location:
23 | description:
24 | fname: "Mary" // tasker fname
25 | Price:
26 | }
27 | },
28 | ]
29 |
30 | taskers: {
31 | 1: {
32 | fname: "John",
33 | lname: "Jacob",
34 | img_url: "",
35 | rating: 8.3,
36 | review_count: 15,
37 | price: 30,
38 | completed: 15,
39 | // help_desc (items being passed onto taskerShow child component, helpDescription.
40 | help_desc: {
41 | pitch: "I am very good at this task",
42 | quote: "This experience was great",
43 | img_url: "/assets/1.png",
44 | date: "03212017"
45 | }
46 | },
47 |
48 | }
49 |
50 |
51 | availabilities {
52 | filter: "top_rated",
53 | "0227": {
54 | "morning": [ 21, 32, 11, 15, 2, 4],
55 | "afternoon": [32, 11,14, 5],
56 | "evening": [32, 15, 4, 6]
57 | },
58 | "0228": {
59 | // key is the date, then time-frame, each time-frame has an array of tasker_ids that are avail during that time.
60 | "morning": [ 21, 32, 11, 15, 2, 4],
61 | "afternoon": [32, 11,14, 5],
62 | "evening": [32, 15, 4, 6]
63 | }
64 | }
65 |
66 | search: {
67 | value: "min",
68 | results: ["minor repairs", "minor work"]
69 | }
70 |
71 | newTask: {
72 | step: 3// what step in the form the user is on.
73 | location: "32 Weave Lane, Wichita, NB, 20132"
74 | locality: "Wichita" // locality from Google API
75 | category_id: 6
76 | title: "Minor Repairs" // category title
77 | tasker_id: 3
78 | date: "03212017"
79 | time: "morning"
80 | description: "Fix the toilet"
81 | errors: {[]}
82 | }
83 |
84 |
85 |
86 | ```
87 |
--------------------------------------------------------------------------------
/docs/schema.md:
--------------------------------------------------------------------------------
1 | # Schema Information
2 |
3 | ## users
4 | column name | data type | details
5 | ----------------|-----------|-----------------------
6 | id | integer | not null, primary key
7 | fname | string | not null
8 | lname | string | not null
9 | email | string | not null, indexed, unique
10 | password_digest | string | not null
11 | session_token | string | not null, indexed, unique
12 | tasker | boolean | not null, default: false, indexed
13 | phone_number | string | not null
14 | zip_code | string | not null, indexed
15 | locality | string | indexed
16 |
17 | ## tasks
18 | column name | data type | details
19 | ------------|-----------|-----------------------
20 | id | integer | not null, primary key
21 | description | text | not null
22 | location | string | not null
23 | locality | string | not null, indexed
24 | date | date | not null,
25 | time | string | not null,
26 | requestor_id| integer | not null, indexed, foreign_key (user)
27 | category_id | integer | not null, indexed, foreign_key (category)
28 | tasker_id | integer | not null, indexed, foreign_key (user)
29 |
30 | ## categories
31 | column name | data type | details
32 | ------------|-----------|-----------------------
33 | id | integer | not null, primary key
34 | title | string | not null, indexed
35 | img_url | string | not null
36 | description | string |
37 |
38 | ## skills
39 | column name | data type | details
40 | ------------ |-----------|-----------------------
41 | id | integer | not null, primary key
42 | tasker_id | integer | not null, indexed
43 | category_id | integer | not null, indexed
44 | pitch | text | not null
45 | price | integer | not null
46 | reviews | array | not null, default: []
47 | quote | text |
48 | quote_author_id | integer |
49 |
50 | ## regions
51 | column name | data type | details
52 | ------------|-----------|-----------------------
53 | id | integer | not null, primary key
54 | user_id | string | not null, unique
55 | locality | string | not null, unique, indexed, foreign_key
56 |
57 | ## availabilities
58 | column name | data type | details
59 | ------------|-----------|-----------------------
60 | id | integer | not null, primary key
61 | tasker_id | integer | not null, foreign key
62 | date | integer | not null
63 | morning | boolean | not null, default: false
64 | afternoon | boolean | not null, default: false
65 | evening | boolean | not null, default: false
66 |
--------------------------------------------------------------------------------
/docs/wireframes/categorySearch.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/docs/wireframes/categorySearch.png
--------------------------------------------------------------------------------
/docs/wireframes/favCategoryIndex.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/docs/wireframes/favCategoryIndex.png
--------------------------------------------------------------------------------
/docs/wireframes/log_in.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/docs/wireframes/log_in.png
--------------------------------------------------------------------------------
/docs/wireframes/newTask.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/docs/wireframes/newTask.png
--------------------------------------------------------------------------------
/docs/wireframes/phase1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/docs/wireframes/phase1.png
--------------------------------------------------------------------------------
/docs/wireframes/phase2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/docs/wireframes/phase2.png
--------------------------------------------------------------------------------
/docs/wireframes/phase3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/docs/wireframes/phase3.png
--------------------------------------------------------------------------------
/docs/wireframes/sign_up.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/docs/wireframes/sign_up.png
--------------------------------------------------------------------------------
/docs/wireframes/taskIndex.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/docs/wireframes/taskIndex.png
--------------------------------------------------------------------------------
/frontend/actions/category_actions.js:
--------------------------------------------------------------------------------
1 | import * as APIUtil from '../util/api_util';
2 |
3 | export const RECEIVE_CATEGORIES = "RECEIVE_CATEGORIES";
4 |
5 | export const fetchCategories = () => dispatch => {
6 | return APIUtil.categories().then(categories => {
7 | return dispatch(receiveCategories(categories));
8 | });
9 | };
10 |
11 | export const receiveCategories = categories => {
12 | return {
13 | type: RECEIVE_CATEGORIES,
14 | categories
15 | };
16 | };
17 |
--------------------------------------------------------------------------------
/frontend/actions/filter_actions.js:
--------------------------------------------------------------------------------
1 | import * as APIUtil from '../util/api_util';
2 | import { filterTaskers } from '../reducers/selectors';
3 | export const RECEIVE_FILTER_RESULTS = "RECEIVE_FILTER_RESULTS";
4 | export const RECEIVE_FILTER = "RECEIVE_FILTER";
5 |
6 | export const receiveFilter = parameter => {
7 | return {
8 | type: RECEIVE_FILTER,
9 | parameter
10 | };
11 | };
12 |
13 | export const receiveFilterResults = taskers => ({
14 | type: RECEIVE_FILTER_RESULTS,
15 | taskers
16 | });
17 |
18 |
19 | export const updateFilter = (parameter) => (dispatch) => {
20 | return dispatch(receiveFilter(parameter));
21 | };
22 |
23 |
24 | export const updateFilterResults = (filters, taskers, availabilities) => (dispatch) => {
25 | const filteredTaskers = filterTaskers(filters, taskers, availabilities);
26 | return dispatch(receiveFilterResults(filteredTaskers));
27 | };
28 |
--------------------------------------------------------------------------------
/frontend/actions/search_actions.js:
--------------------------------------------------------------------------------
1 |
2 | export const UPDATE_SEARCH = "UPDATE_SEARCH";
3 |
4 | export const updateSearch = search => {
5 |
6 | return {
7 | type: UPDATE_SEARCH,
8 | search
9 | };
10 | };
11 |
--------------------------------------------------------------------------------
/frontend/actions/session_actions.js:
--------------------------------------------------------------------------------
1 | import * as APIUtil from '../util/api_util';
2 |
3 | export const RECEIVE_CURRENT_USER = "RECEIVE_CURRENT_USER";
4 | export const RECEIVE_ERRORS = "RECEIVE_ERRORS";
5 |
6 | export const signup = user => dispatch => {
7 | return APIUtil.signup(user)
8 | .then(user => dispatch(receiveCurrentUser(user)),
9 | err => dispatch(receiveErrors(err.responseJSON)));
10 | };
11 |
12 | export const editUser = user => dispatch => {
13 | return APIUtil.edit(user)
14 | .then(user => dispatch(receiveCurrentUser(user)),
15 | err => dispatch(receiveErrors(err.responseJSON)));
16 | };
17 |
18 | export const login = user => dispatch => (
19 | APIUtil.login(user)
20 | .then(user => dispatch(receiveCurrentUser(user)),
21 | err => dispatch(receiveErrors(err.responseJSON)))
22 | );
23 |
24 | export const logout = () => dispatch => (
25 | APIUtil.logout().then(user => dispatch(receiveCurrentUser(null)))
26 | );
27 |
28 | export const receiveCurrentUser = currentUser => ({
29 | type: RECEIVE_CURRENT_USER,
30 | currentUser
31 | });
32 |
33 | export const receiveErrors = errors => ({
34 | type: RECEIVE_ERRORS,
35 | errors
36 | });
37 |
--------------------------------------------------------------------------------
/frontend/actions/stage_actions.js:
--------------------------------------------------------------------------------
1 | export const UPDATE_STAGE = "UPDATE_STAGE";
2 |
3 | export const updateStage = stage => {
4 | return {
5 | type: UPDATE_STAGE,
6 | stage
7 | };
8 | };
9 |
--------------------------------------------------------------------------------
/frontend/actions/task_actions.js:
--------------------------------------------------------------------------------
1 | import * as APIUtil from '../util/api_util';
2 | import { setTask, getTask } from '../components/forms/newTask/session_util';
3 | export const RECEIVE_TASKS = "RECEIVE_TASKS";
4 | export const RECEIVE_TASK = "RECEIVE_TASK";
5 | export const CLEAR_NEW_TASK = "CLEAR_NEW_TASK";
6 | export const RECEIVE_NEW_TASK = 'RECEIVE_NEW_TASK';
7 |
8 | export const clearNewTask = () => {
9 | return {
10 | type: CLEAR_NEW_TASK
11 | }
12 | }
13 |
14 | export const receiveNewTask = task => {
15 | return {
16 | type: RECEIVE_NEW_TASK,
17 | task
18 | };
19 | };
20 |
21 | export const receiveTasks = tasks => {
22 | return {
23 | type: RECEIVE_TASKS,
24 | tasks
25 | };
26 | };
27 |
28 | export const receiveTask = task => {
29 | return {
30 | type: RECEIVE_TASK,
31 | task
32 | };
33 | };
34 |
35 | export const updateNewTask = (task) => dispatch => {
36 | setTask(task);
37 | return dispatch(receiveNewTask(task));
38 | };
39 |
40 | export const fetchTasks = () => dispatch => {
41 | return APIUtil.requestedTasks().then(tasks => {
42 | return dispatch(receiveTasks(tasks));
43 | });
44 |
45 | };
46 |
47 | export const createTask = (task) => dispatch => {
48 | return APIUtil.createTask(task).then((tasks) => {
49 | return dispatch(receiveTasks(task));
50 | });
51 | };
52 |
--------------------------------------------------------------------------------
/frontend/actions/user_actions.js:
--------------------------------------------------------------------------------
1 | import * as APIUtil from '../util/api_util';
2 | import { receiveErrors } from './session_actions';
3 | export const RECEIVE_TASKERS = "RECEIVE_TASKERS";
4 | export const CLEAR_TASKERS = "CLEAR_TASKERS";
5 | export const receiveTaskers = tasker_data => {
6 | return {
7 | type: RECEIVE_TASKERS,
8 | tasker_data
9 | };
10 | };
11 |
12 | export const clearTaskers = () => {
13 | return {
14 | type: CLEAR_TASKERS
15 | };
16 |
17 | };
18 |
19 |
20 | export const getTaskers = (category_id, locality) => dispatch => (
21 | APIUtil.fetchTaskers(category_id, locality)
22 | .then(tasker_data => dispatch(receiveTaskers(tasker_data)),
23 | err => dispatch(receiveErrors(err.responseJSON)))
24 | );
25 |
--------------------------------------------------------------------------------
/frontend/components/account/account.jsx:
--------------------------------------------------------------------------------
1 | import EditContainer from '../forms/sessions/edit_container';
2 | import React from 'react';
3 | class Account extends React.Component {
4 | constructor(props){
5 | super(props);
6 | }
7 |
8 | render() {
9 | return (
10 |
11 |
12 | Account
13 |
14 |
27 |
28 | );
29 | }
30 | }
31 |
32 | export default Account;
33 |
--------------------------------------------------------------------------------
/frontend/components/account/account_container.js:
--------------------------------------------------------------------------------
1 | import { connect } from 'react-redux';
2 | import Account from './account';
3 |
4 | const mapStateToProps = (state, ownProps) => {
5 | return {
6 | currentUser: state.session.currentUser,
7 | errors: state.session.errors
8 | };
9 |
10 | };
11 |
12 |
13 | const mapDispatchToProps = (dispatch, ownProps) => {
14 | return {
15 | };
16 | };
17 |
18 | export default connect(mapStateToProps, mapDispatchToProps)(Account);
19 |
--------------------------------------------------------------------------------
/frontend/components/account/panel/panel.jsx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/frontend/components/account/panel/panel.jsx
--------------------------------------------------------------------------------
/frontend/components/account/panel/panel_container.js:
--------------------------------------------------------------------------------
1 | // import { connect } from 'react-redux';
2 | // import Account from './account';
3 | //
4 | // const mapStateToProps = (state, ownProps) => {
5 | // return {
6 | // currentUser: state.session.currentUser,
7 | // errors: state.session.errors
8 | // };
9 | //
10 | // };
11 | //
12 | //
13 | // const mapDispatchToProps = (dispatch, ownProps) => {
14 | // return {
15 | // };
16 | // };
17 | //
18 | // export default connect(mapStateToProps, mapDispatchToProps)(Edit);
19 |
--------------------------------------------------------------------------------
/frontend/components/app.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Link } from 'react-router';
3 | import NavContainer from './nav/nav_container';
4 | import BottomNav from './nav/bottom_nav';
5 | import store from '../store/store';
6 |
7 |
8 |
9 | const App = ({ children }) =>
10 | {
11 | return (
12 |
13 |
14 |
15 | {children}
16 |
17 |
18 |
);
19 | };
20 |
21 | export default App;
22 |
--------------------------------------------------------------------------------
/frontend/components/dashboard/dashboard_container.js:
--------------------------------------------------------------------------------
1 | import { connect } from 'react-redux';
2 | import dashboard from './dashboard';
3 | import { fetchCategories } from '../../actions/category_actions';
4 | import { asArray } from '../../reducers/selectors';
5 | import { receiveNewTask, updateNewTask } from '../../actions/task_actions';
6 |
7 | const mapStateToProps = (state, ownProps) => {
8 | return {
9 | user: state.session.currentUser,
10 | categories: state.categories
11 | };
12 | };
13 |
14 | const mapDispatchToProps = (dispatch, ownProps) => {
15 | return {
16 | fetchCategories: () => dispatch(fetchCategories()),
17 | receiveNewTask: (task) => dispatch(receiveNewTask(task)),
18 | updateNewTask: (task) => dispatch(updateNewTask(task))
19 | };
20 | };
21 |
22 | export default connect(mapStateToProps, mapDispatchToProps)(dashboard);
23 |
--------------------------------------------------------------------------------
/frontend/components/dashboard/requested_task.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Link, withRouter } from 'react-router';
3 | import TaskDetails from './task_details';
4 | import SmoothCollapse from 'react-smooth-collapse';
5 | class RequestedTask extends React.Component {
6 | constructor(props){
7 | super(props);
8 | this.toggleDetails = this.toggleDetails.bind(this);
9 | this.showDetails = this.showDetails.bind(this);
10 | this.state = {
11 | details: false,
12 | chevron: "icon-chevron-thin-down"
13 | };
14 | }
15 |
16 | toggleDetails(e){
17 | let newDetailState;
18 |
19 | if(this.state.details) {
20 | newDetailState = {
21 | details: false,
22 | chevron: "icon-chevron-thin-down" };
23 | } else {
24 | newDetailState = {
25 | details: true,
26 | chevron: "icon-chevron-thin-up"
27 | };
28 | }
29 |
30 | this.setState(newDetailState);
31 | }
32 |
33 | showDetails(){
34 | if(this.state.details){
35 | return ( );
36 | }
37 | }
38 |
39 |
40 | render(){
41 | const { task } = this.props;
42 | const taskDate = new Date(task.date);
43 | return (
44 |
45 |
46 |
{ task.title }
47 |
48 |

49 |
50 |
51 |
52 |
53 |
54 |
{ taskDate.getDate() }
55 |
{ dateAbrev[taskDate.getMonth()] }
56 |
57 |
58 |
59 | { task.time }
60 |
61 |
62 |
63 | { this.showDetails() }
64 |
65 |
68 |
69 |
70 | );
71 | }
72 | }
73 |
74 | export default RequestedTask;
75 |
--------------------------------------------------------------------------------
/frontend/components/dashboard/requested_tasks.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Link, withRouter } from 'react-router';
3 | import RequestedTask from './requested_task';
4 | import { asArray } from '../../reducers/selectors';
5 |
6 | class RequestedTasks extends React.Component {
7 | constructor(props){
8 | super(props);
9 | }
10 |
11 | componentDidMount(){
12 | this.props.fetchTasks();
13 | }
14 |
15 | render(){
16 | let allTasks = asArray(this.props.tasks).map( (task) => {
17 | return ();
18 | });
19 |
20 | return (
21 |
24 | );
25 |
26 | }
27 |
28 | }
29 |
30 | export default withRouter(RequestedTasks);
31 |
--------------------------------------------------------------------------------
/frontend/components/dashboard/requested_tasks_container.js:
--------------------------------------------------------------------------------
1 | import { connect } from 'react-redux';
2 | import requestedTasks from './requested_tasks';
3 | import { fetchTasks } from '../../actions/task_actions';
4 |
5 |
6 | const mapStateToProps = (state, ownProps) => {
7 | return {
8 | user: state.session.currentUser,
9 | tasks: state.tasks
10 | };
11 | };
12 |
13 | const mapDispatchToProps = (dispatch, ownProps) => {
14 | return {
15 | fetchTasks: () => dispatch(fetchTasks())
16 | };
17 | };
18 |
19 | export default connect(mapStateToProps, mapDispatchToProps)(requestedTasks);
20 |
--------------------------------------------------------------------------------
/frontend/components/dashboard/task_details.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Link, withRouter } from 'react-router';
3 |
4 | class taskDetails extends React.Component {
5 | constructor(props){
6 | super(props);
7 |
8 | }
9 |
10 | render(){
11 | const { details } = this.props;
12 | return (
13 |
14 |
30 |
31 |
34 |
35 |
36 | );
37 | }
38 | }
39 |
40 | export default taskDetails;
41 |
--------------------------------------------------------------------------------
/frontend/components/dashboard/text.jsx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
Easily book n manage tasks n our app
5 |
Please enter your mobile number to receive a download link.
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/frontend/components/forms/newTask/new_task_container.js:
--------------------------------------------------------------------------------
1 | import { connect } from 'react-redux';
2 | import { updateNewTask } from '../../../actions/task_actions';
3 | import newTask from './new_task';
4 | import { getTask } from './session_util';
5 | import { pencilIcon } from '../../helpers/icon_helper';
6 | import { getTaskers } from '../../../actions/user_actions';
7 |
8 | const mapStateToProps = (state, ownProps) => {
9 | return { task: state.task, pencil: pencilIcon(), taskers: state.taskers }
10 | };
11 |
12 | const mapDispatchToProps = (dispatch, ownProps) => ({
13 | updateNewTask: (task) => dispatch(updateNewTask(task)),
14 | getTaskers: (category_id, locality) => dispatch(getTaskers(category_id, locality))
15 | });
16 |
17 |
18 | export default connect(mapStateToProps, mapDispatchToProps)(newTask);
19 |
--------------------------------------------------------------------------------
/frontend/components/forms/newTask/session_util.js:
--------------------------------------------------------------------------------
1 | export const getTask = () => JSON.parse(sessionStorage.getItem("task"));
2 |
3 | export const getStorageTaskers = () => JSON.parse(sessionStorage.getItem("taskers"));
4 |
5 | export const setTask = (task) => sessionStorage.setItem("task", JSON.stringify(task));
6 |
7 | export const setTaskers = (taskers) => sessionStorage.setItem("taskers", JSON.stringify(taskers));
8 |
9 | export const clearTask = () => sessionStorage.clear("task");
10 | export const clearTaskers = () => sessionStorage.clear("taskers");
11 |
--------------------------------------------------------------------------------
/frontend/components/forms/newTask/stage1/stage1.jsx:
--------------------------------------------------------------------------------
1 | import { clearTask } from '../session_util';
2 | import DescriptionContainer from './taskDescription/task_description_container';
3 | import LocationContainer from './taskLocation/location_container';
4 | import { Link } from 'react-router';
5 | import SmoothCollapse from 'react-smooth-collapse';
6 | import React from 'react';
7 |
8 | class Stage1 extends React.Component {
9 | constructor(props){
10 | super(props);
11 | this.state = {
12 | showDescription: false
13 | }
14 | }
15 |
16 | componentWillReceiveProps(newProps) {
17 | let { showDescription: newShowDescription } = newProps.task.toggles;
18 | let { showDescription: oldShowDescription } = this.props.task.toggles;
19 | if(newShowDescription !== oldShowDescription) {
20 | this.setState({ showDescription: newShowDescription });
21 | }
22 | }
23 |
24 | render(){
25 | let { category_title } = this.props.task;
26 |
27 | return (
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 | );
40 | }
41 | }
42 |
43 | export default Stage1;
44 |
--------------------------------------------------------------------------------
/frontend/components/forms/newTask/stage1/stage1_container.js:
--------------------------------------------------------------------------------
1 | import { connect } from 'react-redux';
2 | import Stage1 from './stage1';
3 |
4 | const mapStateToProps = (state, ownProps) => ({ task: state.task });
5 |
6 | export default connect(mapStateToProps)(Stage1);
7 |
--------------------------------------------------------------------------------
/frontend/components/forms/newTask/stage1/taskDescription/task_description.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Link, withRouter } from 'react-router';
3 |
4 | class TaskDescription extends React.Component {
5 | constructor(props){
6 | super(props);
7 | this.handleSubmit = this.handleSubmit.bind(this);
8 | this.clearDescription = this.clearDescription.bind(this);
9 | this.handleDescriptionChange = this.handleDescriptionChange.bind(this);
10 |
11 | this.state = {
12 | default_description: true,
13 | task_description: ""
14 | };
15 | }
16 |
17 | clearDescription(){
18 | if(this.state.default_description){
19 | this.setState({
20 | default_description: false,
21 | task_desc: ""
22 | });
23 | }
24 | }
25 |
26 | handleDescriptionChange(e){
27 | this.setState({
28 | task_description: e.target.value
29 | });
30 | }
31 |
32 | handleSubmit(){
33 | this.props.updateNewTask({
34 | task_description: this.state.task_description,
35 | stage: 2
36 | });
37 |
38 | let { filter, availabilities, taskers } = this.props;
39 | this.props.updateFilterResults(filter, taskers, availabilities);
40 | this.props.router.push('/dashboard/newTask/stage2');
41 | }
42 |
43 | render(){
44 | return (
45 |
46 |
47 |
48 | TELL US ABOUT YOUR TASK
49 |
50 |
51 |
52 | If you need two or more Taskers, please post additional tasks for each Tasker needed.
53 |
54 |
55 |
57 |
58 |
59 |
60 |
61 |
62 |
63 | );
64 | }
65 | }
66 |
67 | export default withRouter(TaskDescription);
68 |
--------------------------------------------------------------------------------
/frontend/components/forms/newTask/stage1/taskDescription/task_description_container.js:
--------------------------------------------------------------------------------
1 | import { connect } from 'react-redux';
2 | import TaskDescription from './task_description';
3 | import { updateNewTask } from '../../../../../actions/task_actions';
4 | import { updateFilterResults } from '../../../../../actions/filter_actions';
5 |
6 | const mapStateToProps = (state, ownProps) => ({
7 | task: state.task,
8 | taskers: state.taskers,
9 | availabilities: state.availabilities,
10 | filter: state.filter
11 | });
12 |
13 | const mapDispatchToProps = (dispatch, ownProps) => ({
14 | updateNewTask: (task) => dispatch(updateNewTask(task)),
15 | updateFilterResults: (filter, taskers, availabilities) => dispatch(updateFilterResults(filter, taskers, availabilities))
16 | });
17 |
18 | export default connect(mapStateToProps, mapDispatchToProps)(TaskDescription);
19 |
--------------------------------------------------------------------------------
/frontend/components/forms/newTask/stage1/taskLocation/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 | export const addAptNumToAddress = (address, apt_num) => {
25 | address_components = address.split(",");
26 |
27 | if(apt_num !== "") {
28 | address_components = address_components
29 | .slice(0, 1)
30 | .concat(apt_num, address_components.slice(-3));
31 | }
32 | return address_components.join(",");
33 | };
34 |
35 | export const getLocalityAndAddress = () => {
36 | let place = this.getPlace();
37 | let locality = "";
38 | let componentForm = { locality: 'long_name' };
39 |
40 | for (var i = 0; i < place.address_components.length; i++) {
41 | let addressType = place.address_components[i].types[0];
42 | if (componentForm[addressType]) {
43 | locality = place.address_components[i][componentForm[addressType]];
44 | console.log(locality);
45 | }
46 | }
47 |
48 | return callback({ locality: locality, address: place.formatted_address });
49 | }
50 |
--------------------------------------------------------------------------------
/frontend/components/forms/newTask/stage1/taskLocation/location.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import LocationFormContainer from './locationForm/location_form_container';
3 | import LocationDisplayContainer from './locationDisplay/location_display_container';
4 | import SmoothCollapse from 'react-smooth-collapse';
5 | class Location extends React.Component {
6 | constructor(props){
7 | super(props);
8 | this.state = { showLocationForm: true };
9 | }
10 |
11 | componentWillReceiveProps(newProps) {
12 | let { showLocationForm: newShowLocationForm } = newProps.task.toggles;
13 | let { showLocationForm: oldShowLocationForm } = this.props.task.toggles;
14 | if(newShowLocationForm !== oldShowLocationForm) {
15 | this.setState({ showLocationForm: newShowLocationForm });
16 | }
17 | }
18 |
19 | render() {
20 |
21 | return (
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 | );
32 | }
33 | }
34 |
35 | export default Location;
36 |
--------------------------------------------------------------------------------
/frontend/components/forms/newTask/stage1/taskLocation/locationDisplay/location_display_container.js:
--------------------------------------------------------------------------------
1 | import { connect } from 'react-redux';
2 | import LocationDisplay from './location_display';
3 | import { updateNewTask } from '../../../../../../actions/task_actions';
4 | import { getTaskers } from '../../../../../../actions/user_actions';
5 |
6 | const mapStateToProps = (state, ownProps) => ({
7 | task: state.task
8 | });
9 |
10 | const mapDispatchToProps = (dispatch, ownProps) => ({
11 | updateNewTask: (task) => dispatch(updateNewTask(task)),
12 | getTaskers: (category_id, locality) => dispatch(getTaskers(category_id, locality))
13 | });
14 |
15 | export default connect(mapStateToProps, mapDispatchToProps)(LocationDisplay);
16 |
--------------------------------------------------------------------------------
/frontend/components/forms/newTask/stage1/taskLocation/locationForm/location_form_container.js:
--------------------------------------------------------------------------------
1 | import { connect } from 'react-redux';
2 | import LocationForm from './location_form';
3 | import { updateNewTask } from '../../../../../../actions/task_actions';
4 | import { getTaskers } from '../../../../../../actions/user_actions';
5 |
6 | const mapStateToProps = (state, ownProps) => ({
7 | task: state.task
8 | });
9 |
10 | const mapDispatchToProps = (dispatch, ownProps) => ({
11 | updateNewTask: (task) => dispatch(updateNewTask(task)),
12 | getTaskers: (category_id, locality) => dispatch(getTaskers(category_id, locality))
13 | });
14 |
15 | export default connect(mapStateToProps, mapDispatchToProps)(LocationForm);
16 |
--------------------------------------------------------------------------------
/frontend/components/forms/newTask/stage1/taskLocation/location_container.js:
--------------------------------------------------------------------------------
1 | import { connect } from 'react-redux';
2 | import Location from './location';
3 |
4 | const mapStateToProps = (state, ownProps) => ({ task: state.task });
5 |
6 | export default connect(mapStateToProps)(Location);
7 |
--------------------------------------------------------------------------------
/frontend/components/forms/newTask/stage2/Stage2.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Link, withRouter } from 'react-router';
3 | import FilterContainer from './filter/filter_container';
4 | import TaskerIdxContainer from './taskers/taskerIdx_container';
5 |
6 | class Stage2 extends React.Component {
7 | constructor(props){
8 | super(props);
9 | }
10 |
11 | render(){
12 | return (
13 |
14 |
15 |
16 |
17 | );
18 | }
19 |
20 | }
21 |
22 | export default withRouter(Stage2);
23 |
--------------------------------------------------------------------------------
/frontend/components/forms/newTask/stage2/filter/Date/date_availability.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { connect } from 'react-redux';
3 | import { updateFilter } from '../../../../../../actions/filter_actions';
4 | class DateAvailability extends React.Component {
5 | constructor(props){
6 | super(props);
7 | this.date = new Date(this.props.date);
8 | this.generateDateString = this.generateDateString.bind(this);
9 | this.handleClick = this.handleClick.bind(this);
10 | }
11 |
12 | generateDateString(){
13 | let year = this.date.getFullYear();
14 | let month = (parseInt(this.date.getMonth()) + 1)
15 | if(month < 10) {
16 | month = month.toString();
17 | month = `0${month}`;
18 | }
19 | let day = this.date.getDate();
20 | if(day < 10) {
21 | day = day.toString();
22 | day = `0${day}`;
23 | }
24 |
25 | return `${year}-${month}-${day}`;
26 | }
27 |
28 | handleClick(e){
29 | this.props.updateFilter({date: this.generateDateString()});
30 | }
31 |
32 | render(){
33 | return (
34 |
35 |
36 |
37 |
38 | );
39 |
40 | }
41 |
42 | }
43 |
44 |
45 |
46 | const mapStateToProps = (state, ownProps) => {
47 | return {
48 | filter: state.filter
49 | };
50 | };
51 |
52 | const mapDispatchToProps = (dispatch, ownProps) => {
53 | return {
54 | updateFilter: (parameters) => dispatch(updateFilter(parameters))
55 | };
56 | };
57 |
58 | export default connect(mapStateToProps, mapDispatchToProps)(DateAvailability);
59 |
--------------------------------------------------------------------------------
/frontend/components/forms/newTask/stage2/filter/Date/date_carousel.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Slider from 'react-slick';
3 | import { uniqTaskers, asArray } from '../../../../../../reducers/selectors.js';
4 | import DateAvailability from './date_availability';
5 |
6 | class DateCarousel extends React.Component {
7 | constructor(props){
8 | super(props);
9 | this.dateAvailabilities = this.dateAvailabilities.bind(this);
10 | this.settings = {
11 | centerMode: true,
12 | infinite: true,
13 | slidesToShow: 3,
14 | speed: 500,
15 | variableWidth: false,
16 | focusOnSelect: true,
17 | };
18 | }
19 |
20 | dateAvailabilities(){
21 | return Object.keys(this.props.availabilities).map( (date, idx) => {
22 | let taskers = [];
23 | this.props.availabilities[date].forEach( (time_slot) => {
24 | if(!taskers.includes(time_slot.tasker_id)){
25 | taskers.push(time_slot.tasker_id);
26 | }
27 | });
28 | return (
);
29 | });
30 | }
31 |
32 |
33 | render(){
34 |
35 | const dates = this.dateAvailabilities();
36 | if(dates.length === 0){
37 | return (
);
38 | } else {
39 | return (
40 |
41 | {dates}
42 | );
43 | }
44 |
45 | }
46 | }
47 |
48 |
49 |
50 | export default DateCarousel;
51 |
--------------------------------------------------------------------------------
/frontend/components/forms/newTask/stage2/filter/Date/date_container.js:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/frontend/components/forms/newTask/stage2/filter/Time/time.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 |
4 | class Time extends React.Component {
5 | constructor(props){
6 | super(props);
7 | this.handleSelect = this.handleSelect.bind(this);
8 | }
9 |
10 | handleSelect(e){
11 | e.preventDefault();
12 | this.props.updateFilter({time: e.target.value});
13 | }
14 |
15 | render() {
16 | return (
17 |
23 | );
24 | }
25 | }
26 |
27 | export default Time;
28 |
--------------------------------------------------------------------------------
/frontend/components/forms/newTask/stage2/filter/Time/time_container.js:
--------------------------------------------------------------------------------
1 | import { connect } from 'react-redux';
2 | import Time from './time';
3 | import { updateFilter } from '../../../../../../actions/filter_actions';
4 |
5 | const mapStateToProps = (state, ownProps) => ({
6 | time: state.filter.time
7 | });
8 |
9 | const mapDispatchToProps = (dispatch, ownProps) => ({
10 | updateFilter: (parameter) => dispatch(updateFilter(parameter))
11 | });
12 |
13 | export default connect(mapStateToProps, mapDispatchToProps)(Time);
14 |
--------------------------------------------------------------------------------
/frontend/components/forms/newTask/stage2/filter/filter_container.js:
--------------------------------------------------------------------------------
1 | import { connect } from 'react-redux';
2 | import Filter from './filter';
3 | import { updateFilter, updateFilterResults } from '../../../../../actions/filter_actions';
4 | const mapStateToProps = (state, ownProps) => ({
5 | taskers: state.taskers,
6 | availabilities: state.availabilities,
7 | filter: state.filter
8 | });
9 |
10 | const mapDispatchToProps = (dispatch, ownProps) => ({
11 | updateFilterResults: (filters, taskers, availabilities) => dispatch(updateFilterResults(filters, taskers, availabilities)),
12 | updateFilter: (parameter) => dispatch(updateFilter(parameter))
13 | });
14 |
15 | export default connect(mapStateToProps, mapDispatchToProps)(Filter);
16 |
--------------------------------------------------------------------------------
/frontend/components/forms/newTask/stage2/filter/sorted_by.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { generateSort } from '../../../../../util/sort_util';
3 |
4 | class sortedBy extends React.Component {
5 | constructor(props){
6 | super(props);
7 | this.handleSelect = this.handleSelect.bind(this);
8 | }
9 |
10 | handleSelect(e){
11 | e.preventDefault();
12 |
13 | const sortFilters = {
14 | price_asc: { direction: 'asc', val: 'price' },
15 | price_desc: { direction: 'desc', val: 'price' },
16 | rating: { direction: 'desc', 'val': 'rating' },
17 | review_count: { direction: 'desc', val: 'review_count' }
18 | }
19 | this.props.updateFilter({sorted_by: sortFilters[e.target.value]});
20 | }
21 |
22 | render() {
23 | return (
24 |
25 |
SORTED BY:
26 |
32 |
33 | );
34 | }
35 | }
36 |
37 | export default sortedBy;
38 |
--------------------------------------------------------------------------------
/frontend/components/forms/newTask/stage2/stage2_container.js:
--------------------------------------------------------------------------------
1 | import { connect } from 'react-redux';
2 | import Stage2 from './Stage2';
3 |
4 | const mapStateToProps = (state, ownProps) => ({ task: state.task });
5 |
6 | export default connect(mapStateToProps)(Stage2);
7 |
--------------------------------------------------------------------------------
/frontend/components/forms/newTask/stage2/taskers/tasker.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Link, withRouter } from 'react-router';
3 |
4 | class Tasker extends React.Component {
5 | constructor(props){
6 | super(props);
7 | this.handleSelect = this.handleSelect.bind(this);
8 | }
9 |
10 | handleSelect(){
11 | let { tasker, filter, router, updateNewTask } = this.props;
12 | updateNewTask ({
13 | tasker_id: tasker.id,
14 | date: filter.date,
15 | time: filter.time,
16 | stage: 3
17 | });
18 | router.push('/dashboard/newTask/stage3');
19 | }
20 |
21 | render(){
22 | let { tasker, task } = this.props;
23 | return (
24 |
25 |
26 |

27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
{tasker.fname} {tasker.lname_initial}
${tasker.price}/hr
35 |
{tasker.task_count} {task.category_title} Jobs Completed
36 |
{tasker.review_count} {task.category_title} Reviews ({tasker.rating}% Positive)
37 |
38 |
39 |
40 |
How I can help:
41 |
{tasker.pitch}
42 |
43 |

44 |
{tasker.quote}
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 | );
53 | }
54 | }
55 |
56 | export default withRouter(Tasker);
57 |
--------------------------------------------------------------------------------
/frontend/components/forms/newTask/stage2/taskers/taskerIdx.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import TaskerContainer from './tasker_container';
3 | import { Link } from 'react-router';
4 |
5 | class TaskerIdx extends React.Component {
6 | constructor(props){
7 | super(props);
8 | this.noResults = this.noResults.bind(this);
9 | }
10 |
11 | noResults(){
12 | return (
13 |
14 |
18 |
19 | );
20 | }
21 |
22 | render() {
23 | let taskerResults = "Sorry no results!";
24 | console.log(this.props.results);
25 | taskerResults = this.props.results.map( (tasker) => {
26 | return (
27 |
28 | );
29 | });
30 |
31 |
32 | return (
33 |
34 | { taskerResults }
35 |
36 | );
37 | }
38 | }
39 |
40 | export default TaskerIdx;
41 |
--------------------------------------------------------------------------------
/frontend/components/forms/newTask/stage2/taskers/taskerIdx_container.js:
--------------------------------------------------------------------------------
1 | import { connect } from 'react-redux';
2 | import TaskerIdx from './taskerIdx';
3 | import { updateFilterResults } from '../../../../../actions/filter_actions';
4 | const mapStateToProps = (state, ownProps) => ({
5 | results: state.filter.results
6 | });
7 |
8 | export default connect(mapStateToProps)(TaskerIdx);
9 |
--------------------------------------------------------------------------------
/frontend/components/forms/newTask/stage2/taskers/tasker_container.js:
--------------------------------------------------------------------------------
1 | import { connect } from 'react-redux';
2 | import Tasker from './tasker';
3 | import { updateNewTask } from '../../../../../actions/task_actions';
4 |
5 | const mapStateToProps = (state, ownProps) => ({
6 | task: state.task,
7 | tasker: ownProps.tasker,
8 | filter: state.filter
9 | });
10 |
11 | const mapDispatchToProps = (dispatch, ownProps) => ({
12 | updateNewTask: (task) => dispatch(updateNewTask(task))
13 | });
14 |
15 | export default connect(mapStateToProps, mapDispatchToProps)(Tasker);
16 |
--------------------------------------------------------------------------------
/frontend/components/forms/newTask/stage3/confirm.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Link, withRouter } from 'react-router';
3 | import { parseTask } from '../../../../reducers/selectors';
4 | class Confirm extends React.Component {
5 | constructor(props){
6 | super(props);
7 | this.handleSubmit = this.handleSubmit.bind(this);
8 | this.state = { errors: "" };
9 | this.parseTask = parseTask;
10 | }
11 |
12 | handleSubmit(e){
13 | this.props.createTask(this.parseTask(this.props.task));
14 | this.props.router.push('/dashboard');
15 | }
16 |
17 | render(){
18 | return (
19 |
20 |
22 |
You are only charged after your task is complete.
23 | { this.state.errors }
24 |
25 | );
26 | }
27 | }
28 |
29 | export default withRouter(Confirm);
30 |
--------------------------------------------------------------------------------
/frontend/components/forms/newTask/stage3/confirm_container.js:
--------------------------------------------------------------------------------
1 | import { connect } from 'react-redux';
2 | import Confirm from './confirm';
3 | import { createTask } from '../../../../actions/task_actions';
4 |
5 | const mapStateToProps = (state, ownProps) => ({
6 | task: state.task
7 | });
8 |
9 | const mapDispatchToProps = (dispatch, ownProps) => ({
10 | createTask: (task) => dispatch(createTask(task))
11 | });
12 |
13 | export default connect(mapStateToProps, mapDispatchToProps)(Confirm);
14 |
--------------------------------------------------------------------------------
/frontend/components/forms/newTask/stage3/stage3.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ConfirmAndBook from './confirm_container';
3 | import TaskRecap from './task_recap';
4 |
5 | class Stage3 extends React.Component {
6 | constructor(props){
7 | super(props);
8 | }
9 |
10 | render(){
11 | return (
12 |
13 |
14 |
15 |
16 | );
17 | }
18 |
19 | }
20 |
21 | export default Stage3;
22 |
--------------------------------------------------------------------------------
/frontend/components/forms/newTask/stage3/stage3_container.js:
--------------------------------------------------------------------------------
1 | import { connect } from 'react-redux';
2 | import Stage3 from './stage3';
3 |
4 | const mapStateToProps = (state, ownProps) => ({ task: state.task });
5 |
6 | export default connect(mapStateToProps)(Stage3);
7 |
--------------------------------------------------------------------------------
/frontend/components/forms/newTask/stage3/task_recap.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { connect } from 'react-redux';
3 | import { updateNewTask } from '../../../../actions/task_actions';
4 |
5 | class TaskRecap extends React.Component {
6 | constructor(props){
7 | super(props)
8 | this.handleDescription = this.handleDescription.bind(this);
9 |
10 | }
11 |
12 | handleDescription(e){
13 | this.props.updateNewTask({description: e.target.value});
14 | }
15 |
16 | render(){
17 | let { date, time, address, task_description, category_title } = this.props.task;
18 | let { tiny_avatar_url, fname, lname_initial, price } = this.props.tasker;
19 |
20 | return (
21 |
22 |
23 |
{ category_title }
24 | ${ price }/hr
25 |
26 |
27 |
28 |
29 |
32 |
33 | { date } { time }
34 |
35 |
36 |
37 |
38 |
39 |
42 |
43 | { fname } {lname_initial}
44 |
45 |
46 |
47 |
48 |
49 |
50 |
53 |
54 | { address }
55 |
56 |
57 |
58 |
59 |
60 |
63 |
66 |
67 |
68 | );
69 | }
70 | }
71 |
72 | const mapStateToProps = (state, ownProps) => {
73 | return {
74 | task: state.task,
75 | tasker: state.taskers[state.task.tasker_id]
76 | };
77 |
78 | };
79 |
80 | const mapDispatchToProps = (dispatch, ownProps) => ({
81 | updateNewTask: (task) => dispatch(updateNewTask(task))
82 | });
83 |
84 | export default connect(mapStateToProps, mapDispatchToProps)(TaskRecap);
85 |
--------------------------------------------------------------------------------
/frontend/components/forms/sessions/account_details.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Link, withRouter } from 'react-router';
3 | class AccountDetails extends React.Component {
4 | constructor(props){
5 | super(props);
6 | }
7 |
8 | render(){
9 |
10 | let { img_url_med, fname, lname, email, zip_code, phone_number } = this.props.user;
11 | return (
12 |
13 |
14 |

15 |
16 |
50 |
51 | );
52 | }
53 | }
54 | export default AccountDetails;
55 |
--------------------------------------------------------------------------------
/frontend/components/forms/sessions/edit.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Link, withRouter } from 'react-router';
3 | import EditFormContainer from './edit_form_container';
4 | import AccountDetails from './account_details';
5 | class Edit extends React.Component {
6 | constructor(props){
7 | super(props);
8 | this.state = {
9 | active: false
10 | }
11 | this.handleEdit = this.handleEdit.bind(this);
12 | }
13 |
14 | handleEdit(e){
15 | e.preventDefault();
16 | if(this.state.active){
17 | this.setState({active: false});
18 | } else {
19 | this.setState({active: true});
20 | }
21 | }
22 |
23 | render() {
24 | let { user, logout } = this.props;
25 |
26 | let { active } = this.state;
27 | const edit = () => ();
28 | const details = () => {
29 | return ();
30 | };
31 | const btn = (desc) => (
32 |
35 | );
36 |
37 | let editBtn = active ? btn("Cancel") : btn("Edit");
38 | let main = active ? edit() : details();
39 | return (
40 |
41 |
42 | Account
43 | { editBtn }
44 |
45 | { main }
46 |
47 | );
48 | }
49 | }
50 | export default Edit;
51 |
--------------------------------------------------------------------------------
/frontend/components/forms/sessions/edit_container.js:
--------------------------------------------------------------------------------
1 | import { connect } from 'react-redux';
2 | import Edit from './edit';
3 | import {logout} from '../../../actions/session_actions';
4 |
5 | const mapStateToProps = (state, ownProps) => {
6 | return {
7 | user: state.session.currentUser
8 | };
9 |
10 | };
11 |
12 |
13 | const mapDispatchToProps = (dispatch, ownProps) => {
14 | return {
15 | logout: () => dispatch(logout())
16 | };
17 | };
18 |
19 | export default connect(mapStateToProps, mapDispatchToProps)(Edit);
20 |
--------------------------------------------------------------------------------
/frontend/components/forms/sessions/edit_form.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Link, withRouter } from 'react-router';
3 | class EditForm extends React.Component {
4 | constructor(props){
5 | super(props);
6 | let { fname, lname, email, phone_number, zip_code } = this.props.user;
7 | this.state = {
8 | fname: fname,
9 | lname: lname,
10 | email: email,
11 | phone_number: phone_number,
12 | zip_code: zip_code
13 | };
14 |
15 | this.handleSubmit = this.handleSubmit.bind(this);
16 | this.update = this.update.bind(this);
17 | this.userInput = this.userInput.bind(this);
18 | }
19 |
20 |
21 | userInput(type, title, key, state, clname){
22 | // const err = this.props.errors[key] ? " err" : "";
23 | return (
24 |
28 | );
29 | }
30 |
31 | update(field){
32 | return (e) => {
33 | return this.setState({
34 | [field]: e.currentTarget.value
35 | });
36 | };
37 | }
38 |
39 | handleSubmit(e){
40 | e.preventDefault();
41 | let { id } = this.props.user;
42 | let { fname, lname, zip_code, email, phone_number } = this.state;
43 | this.props.editUser({id, fname, lname, zip_code, email, phone_number});
44 | }
45 |
46 | render() {
47 | const fnameInput = this.userInput("text", "First Name", "fname", this.state.fname, "name-label");
48 |
49 | const lnameInput = this.userInput("text", "Last Name", "lname", this.state.lname, "name-label");
50 |
51 | const zipCodeInput = this.userInput("text", "Zip Code", "zip_code", this.state.zip_code);
52 |
53 | const emailAddressInput = this.userInput("text", "Email Address", "email", this.state.email);
54 |
55 | const phoneInput = this.userInput("text", "Phone Number", "phone_number", this.state.phone_number);
56 |
57 | return (
58 |
59 |
60 |

61 |
62 |
80 |
81 | );
82 | }
83 | }
84 |
85 | export default EditForm;
86 |
--------------------------------------------------------------------------------
/frontend/components/forms/sessions/edit_form_container.js:
--------------------------------------------------------------------------------
1 | import { connect } from 'react-redux';
2 | import EditForm from './edit_form';
3 | import { editUser, receiveErrors } from '../../../actions/session_actions';
4 |
5 |
6 | const mapStateToProps = (state, ownProps) => {
7 | return {
8 | user: state.session.currentUser,
9 | errors: state.session.errors
10 | };
11 |
12 | };
13 |
14 |
15 | const mapDispatchToProps = (dispatch, ownProps) => {
16 | return {
17 | editUser: (user) => dispatch(editUser(user)),
18 | clearErrors: () => dispatch(receiveErrors({})),
19 | receiveError: (error) => dispatch(receiveErrors(error))
20 | };
21 | };
22 |
23 | export default connect(mapStateToProps, mapDispatchToProps)(EditForm);
24 |
--------------------------------------------------------------------------------
/frontend/components/forms/sessions/session_form_container.js:
--------------------------------------------------------------------------------
1 | import { connect } from 'react-redux';
2 | import sessionForm from './session_form';
3 | import { login, logout, signup, receiveErrors } from '../../../actions/session_actions';
4 | import { updateNewTask } from '../../../actions/task_actions';
5 |
6 | const isSignUp = (formType) => Boolean(formType === 'signup');
7 |
8 | const mapStateToProps = (state, ownProps) => {
9 | const formType = ownProps.location.pathname.slice(1);
10 | return {
11 | isSignUp: isSignUp(formType),
12 | loggedIn: state.session.currentUser,
13 | formType: formType,
14 | errors: state.session.errors,
15 | redirect: state.task.redirect
16 | };
17 |
18 | };
19 |
20 |
21 | const mapDispatchToProps = (dispatch, ownProps) => {
22 | const formType = ownProps.location.pathname.slice(1);
23 | const processForm = isSignUp(formType) ? signup : login;
24 | return {
25 | signup: (user) => dispatch(signup(user)),
26 | login: (credentials) => dispatch(login(credentials)),
27 | clearErrors: () => dispatch(receiveErrors({})),
28 | receiveError: (error) => dispatch(receiveErrors(error)),
29 | updateNewTask: (task) => dispatch(updateNewTask(task))
30 | };
31 | };
32 |
33 | export default connect(mapStateToProps, mapDispatchToProps)(sessionForm);
34 |
--------------------------------------------------------------------------------
/frontend/components/forms/sessions/signup.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | class signUpForm extends React.Component {
4 | constructor(props){
5 | super(props);
6 | this.handleSubmit = this.props.handleSubmit;
7 | this.update = this.props.update;
8 | this.user = this.props.user;
9 | }
10 |
11 | render(){
12 | return (
13 |
21 | );
22 |
23 | }
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/frontend/components/helpers/icon_helper.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | export const generateIcon = (name) => {
4 | return ();
5 | }
6 | export const pencilIcon = () => generateIcon('icon-pencil');
7 | export const checkIcon = generateIcon('icon-checkmark step-icon');
8 | export const locationIcon = generateIcon('icon-location2');
9 |
--------------------------------------------------------------------------------
/frontend/components/nav/bottom_nav.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Link, withRouter } from 'react-router';
3 |
4 | class BottomNav extends React.Component {
5 | constructor(props){
6 | super(props);
7 | }
8 |
9 | render(){
10 | return (
11 |
72 |
73 | );
74 |
75 | }
76 |
77 | }
78 |
79 |
80 | export default withRouter(BottomNav);
81 |
--------------------------------------------------------------------------------
/frontend/components/nav/nav.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Link, withRouter } from 'react-router';
3 |
4 | class Nav extends React.Component {
5 | constructor(props){
6 | super(props);
7 | this.handleLogOut = this.handleLogOut.bind(this);
8 | this.sessionLinks = this.sessionLinks.bind(this);
9 | this.handleDemo = this.handleDemo.bind(this);
10 | }
11 |
12 |
13 | componentWillReceiveProps(newProps) {
14 | if(newProps.loggedIn !== this.props.loggedIn) {
15 | if(newProps.loggedIn === null) {
16 | this.props.router.push('/login');
17 | }
18 | }
19 | }
20 |
21 | handleLogOut(){
22 | this.props.logout();
23 | }
24 |
25 | handleDemo(){
26 | const guestUser = {
27 | user: {
28 | email: 'guest@classrabbit.com',
29 | password: 'starwars'
30 | }
31 | };
32 | this.props.login(guestUser);
33 |
34 | }
35 |
36 | sessionLinks(){
37 | if(this.props.loggedIn){
38 | return (
39 |
Log Out
40 |
Dashboard
41 |
Account
42 |
);
43 | } else {
44 | return(
45 |
46 |
Log In
47 |
Sign Up
48 |
Demo
49 |
50 | );
51 | }
52 | }
53 |
54 | render(){
55 | return (
56 |
57 |
58 |
59 |
Class
60 |
61 |

62 |
63 |
64 | { this.sessionLinks() }
65 |
66 | );
67 |
68 | }
69 |
70 | }
71 |
72 |
73 | export default withRouter(Nav);
74 |
--------------------------------------------------------------------------------
/frontend/components/nav/nav_container.js:
--------------------------------------------------------------------------------
1 | import { connect } from 'react-redux';
2 | import Nav from './nav';
3 | import { logout, login } from '../../actions/session_actions';
4 |
5 | const mapStateToProps = (state, ownProps) => {
6 | return {
7 | loggedIn: state.session.currentUser
8 | };
9 |
10 | };
11 |
12 |
13 | const mapDispatchToProps = (dispatch, ownProps) => {
14 | return {
15 | logout: () => dispatch(logout()),
16 | login: (user) => dispatch(login(user))
17 | };
18 |
19 | };
20 |
21 | export default connect(mapStateToProps, mapDispatchToProps)(Nav);
22 |
--------------------------------------------------------------------------------
/frontend/components/search/search_container.js:
--------------------------------------------------------------------------------
1 | import { connect } from 'react-redux';
2 | import Search from './search';
3 | import { updateSearch } from '../../actions/search_actions';
4 | import { asArray } from '../../reducers/selectors';
5 |
6 | const mapStateToProps = (state, ownProps) => {
7 | return {
8 | searchResults: state.search.results,
9 | data: ownProps.data,
10 | handleSelect: ownProps.handleSelect
11 | };
12 | };
13 |
14 | const mapDispatchToProps = (dispatch, ownProps) => {
15 | return {
16 | updateSearch: () => dispatch(updateSearch())
17 | };
18 | };
19 |
20 | export default connect(mapStateToProps, mapDispatchToProps)(Search);
21 |
--------------------------------------------------------------------------------
/frontend/components/splashPage/splash_page.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Link, withRouter } from 'react-router';
3 | import Search from '../search/search';
4 |
5 | class SplashPage extends React.Component {
6 | constructor(props){
7 | super(props);
8 | this.handleSplashSelect = this.handleSplashSelect.bind(this);
9 | this.redirectIfLoggedIn = this.redirectIfLoggedIn.bind(this);
10 | this.handleButton = this.handleButton.bind(this);
11 | }
12 |
13 | componentDidMount(){
14 | this.props.fetchCategories();
15 | }
16 |
17 | componentDidUpdate() {
18 | this.redirectIfLoggedIn();
19 | }
20 |
21 | redirectIfLoggedIn(){
22 | if(this.props.user){
23 | if(!this.props.redirect){
24 | this.props.router.push('/dashboard');
25 | }
26 | }
27 | }
28 |
29 | handleButton(){
30 | this.props.updateNewTask({ category_id: 3, category_title: this.props.categories[3].title, stage: 1, redirect: true});
31 |
32 | this.props.router.push('/dashboard/newTask/stage1');
33 | }
34 |
35 | handleSplashSelect(category_id){
36 | return () => {
37 | this.props.updateNewTask({ category_id: category_id, category_title: this.props.categories[category_id].title, stage: 1, redirect: true});
38 | };
39 | }
40 |
41 | render(){
42 |
43 | return (
44 |
45 |
46 |
47 |
48 | Help With Your Classroom
49 |
50 |
51 |
52 |
53 | Copies, ordering & more all without leaving your classroom. So you can focus on what matters.
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 | Get Inspired.
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 | Tackle those projects when you need them to be tackled.
71 |
72 |
73 |
74 |
75 |
76 | );
77 | }
78 | }
79 |
80 | export default withRouter(SplashPage);
81 |
--------------------------------------------------------------------------------
/frontend/components/splashPage/splash_page_container.js:
--------------------------------------------------------------------------------
1 | import { connect } from 'react-redux';
2 | import SplashPage from './splash_page';
3 | import { fetchCategories } from '../../actions/category_actions';
4 | import { asArray } from '../../reducers/selectors';
5 | import { receiveNewTask, updateNewTask } from '../../actions/task_actions';
6 |
7 | const mapStateToProps = (state, ownProps) => {
8 | return {
9 | user: state.session.currentUser,
10 | categories: state.categories,
11 | redirect: state.task.redirect
12 | };
13 | };
14 |
15 | const mapDispatchToProps = (dispatch, ownProps) => {
16 | return {
17 | fetchCategories: () => dispatch(fetchCategories()),
18 | receiveNewTask: (task) => dispatch(receiveNewTask(task)),
19 | updateNewTask: (task) => dispatch(updateNewTask(task))
20 | };
21 | };
22 |
23 | export default connect(mapStateToProps, mapDispatchToProps)(SplashPage);
24 |
--------------------------------------------------------------------------------
/frontend/index.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import Root from './components/root';
4 | import configureStore from './store/store';
5 |
6 | document.addEventListener('DOMContentLoaded', () => {
7 | let store;
8 | if (window.currentUser) {
9 | const preloadedState = { session: { currentUser: window.currentUser } };
10 | store = configureStore(preloadedState);
11 | } else {
12 | store = configureStore();
13 | }
14 |
15 | window.store = store;
16 | const root = document.getElementById('root');
17 | ReactDOM.render(, root);
18 | });
19 |
--------------------------------------------------------------------------------
/frontend/reducers/availability_reducer.js:
--------------------------------------------------------------------------------
1 | import { RECEIVE_TASKERS } from '../actions/user_actions';
2 | import merge from 'lodash/merge';
3 |
4 | const initialState = {};
5 |
6 | const AvailabilitiesReducer = (state = initialState, action) => {
7 | Object.freeze(state);
8 | switch(action.type) {
9 | case RECEIVE_TASKERS:
10 | return action.tasker_data.availabilities;
11 | default:
12 | return state;
13 | }
14 | };
15 |
16 | export default AvailabilitiesReducer;
17 |
--------------------------------------------------------------------------------
/frontend/reducers/category_reducer.js:
--------------------------------------------------------------------------------
1 | import { RECEIVE_CATEGORIES } from '../actions/category_actions';
2 | import merge from 'lodash/merge';
3 |
4 | const initialState = {
5 | 1: "done"
6 | };
7 |
8 | const CategoriesReducer = (state = initialState, action) => {
9 | Object.freeze(state);
10 | switch(action.type) {
11 | case RECEIVE_CATEGORIES:
12 | return action.categories;
13 | default:
14 | return state;
15 | }
16 | };
17 |
18 | export default CategoriesReducer;
19 |
--------------------------------------------------------------------------------
/frontend/reducers/filter_reducer.js:
--------------------------------------------------------------------------------
1 | import { RECEIVE_FILTER, RECEIVE_FILTER_RESULTS } from '../actions/filter_actions';
2 | import { RECEIVE_TASKERS } from '../actions/user_actions';
3 | import { generateDateString } from '../util/date_util';
4 |
5 | import { generateSort } from '../util/sort_util';
6 | import { asArray } from './selectors';
7 |
8 | const currentDate = () => {
9 | let todayDate = new Date();
10 | return generateDateString(todayDate);
11 | };
12 |
13 | const _defaultFilter = Object.freeze({
14 | sorted_by: {
15 | direction: 'asc',
16 | val: 'price'
17 | },
18 | date: currentDate(),
19 | time: "Anytime",
20 | results: []
21 | });
22 |
23 | const FilterReducer = (state = _defaultFilter, action) => {
24 | Object.freeze(state);
25 | switch(action.type) {
26 | case RECEIVE_FILTER_RESULTS:
27 | const newResults = Object.assign({}, state);
28 | newResults.results = asArray(action.taskers);
29 | return newResults;
30 | case RECEIVE_FILTER:
31 | return Object.assign({}, state, action.parameter);
32 | case RECEIVE_TASKERS:
33 | if(action.tasker_data.present !== "false") {
34 | const updatedResults = Object.assign({}, state);
35 | updatedResults.results = asArray(action.tasker_data.taskers);
36 | return updatedResults;
37 | } else {
38 | return state;
39 | }
40 | default:
41 | return state;
42 | }
43 | };
44 |
45 | export default FilterReducer;
46 |
--------------------------------------------------------------------------------
/frontend/reducers/new_task_reducer.js:
--------------------------------------------------------------------------------
1 | import { RECEIVE_NEW_TASK, CLEAR_NEW_TASK } from '../actions/task_actions';
2 | import { RECEIVE_TASKERS } from '../actions/user_actions';
3 | import merge from 'lodash/merge';
4 | import { clearTask, setTask } from '../components/forms/newTask/session_util';
5 | const _initialNewTask = Object.freeze({
6 | stage: 1,
7 | present: "",
8 | toggles: {
9 | showDescription: false,
10 | showLocationForm: true,
11 | showErrors: false
12 | },
13 | redirect: false
14 | });
15 |
16 |
17 | const newTaskReducer = (state = _initialNewTask, action) => {
18 |
19 | Object.freeze(state);
20 | switch(action.type) {
21 | case RECEIVE_NEW_TASK:
22 | const newTaskState = Object.assign({}, state, action.task);
23 | setTask({ task: newTaskState});
24 | return newTaskState;
25 | case RECEIVE_TASKERS:
26 | const present = {present: action.tasker_data.present};
27 | const newTaskStateWithTaskerPresence = Object.assign({}, state, present);
28 | setTask({ task: newTaskStateWithTaskerPresence});
29 | return newTaskStateWithTaskerPresence;
30 | case CLEAR_NEW_TASK:
31 | clearTask();
32 | return _initialNewTask;
33 | default:
34 | return state;
35 | }
36 | };
37 |
38 | export default newTaskReducer;
39 |
--------------------------------------------------------------------------------
/frontend/reducers/root_reducer.js:
--------------------------------------------------------------------------------
1 | import { combineReducers } from 'redux';
2 | import categoryReducer from './category_reducer';
3 | import taskReducer from './task_reducer';
4 | import sessionReducer from './session_reducer';
5 | import searchReducer from './search_reducer';
6 | import newTaskReducer from './new_task_reducer';
7 | import availabilitiesReducer from './availability_reducer';
8 | import taskerReducer from './tasker_reducer';
9 | import filterReducer from './filter_reducer';
10 | import stageReducer from './stage_reducer';
11 |
12 | const rootReducer = combineReducers({
13 | session: sessionReducer,
14 | categories: categoryReducer,
15 | search: searchReducer,
16 | tasks: taskReducer,
17 | task: newTaskReducer,
18 | availabilities: availabilitiesReducer,
19 | taskers: taskerReducer,
20 | filter: filterReducer,
21 | stage: stageReducer
22 | });
23 |
24 | export default rootReducer;
25 |
--------------------------------------------------------------------------------
/frontend/reducers/search_reducer.js:
--------------------------------------------------------------------------------
1 | import merge from 'lodash/merge';
2 | import { UPDATE_SEARCH } from '../actions/search_actions';
3 | const _defaultSearch = Object.freeze({
4 | value: "",
5 | results: [],
6 | active: "hidden"
7 | });
8 |
9 | const SearchReducer = (state = _defaultSearch, action) => {
10 | Object.freeze(state);
11 | switch(action.type) {
12 | case UPDATE_SEARCH:
13 | return action.search;
14 | default:
15 | return state;
16 | }
17 | };
18 |
19 | export default SearchReducer;
20 |
--------------------------------------------------------------------------------
/frontend/reducers/selectors.js:
--------------------------------------------------------------------------------
1 | import { generateSort } from '../util/sort_util';
2 |
3 | export const asArray = (categories) => {
4 | return Object.keys(categories).map((key) => {
5 | return categories[key];
6 | });
7 | };
8 |
9 | export const uniqTaskers = (availabilities) => {
10 | asArray(this.props.availabilities).map( (availability) => {
11 | return taskers;
12 | });
13 | };
14 |
15 | export const parseTask = (task) => {
16 |
17 | let { tasker_id, locality, category_id, time, date, task_description: description, address: location } = task;
18 | return { tasker_id, locality, category_id, time, date, description, location };
19 | };
20 |
21 |
22 | export const filterTaskers = (filters, taskers, availabilities) => {
23 | let filteredTaskers = {};
24 | if(availabilities[filters.date] === undefined) {
25 | return [];
26 | }
27 | availabilities[filters.date].forEach( (availability) => {
28 | if(availability.time === filters.time){
29 | filteredTaskers[availability.tasker_id] = taskers[availability.tasker_id];
30 | }
31 | });
32 |
33 | let { direction, val } = filters.sorted_by;
34 | filteredTaskers = asArray(filteredTaskers).sort( (tasker1, tasker2) => {
35 | return generateSort(direction, val)(tasker1, tasker2);
36 | });
37 | return filteredTaskers;
38 | };
39 |
--------------------------------------------------------------------------------
/frontend/reducers/session_reducer.js:
--------------------------------------------------------------------------------
1 | import { RECEIVE_CURRENT_USER, RECEIVE_ERRORS } from '../actions/session_actions';
2 | import merge from 'lodash/merge';
3 |
4 | const _nullUser = Object.freeze({
5 | currentUser: null,
6 | errors: []
7 | });
8 |
9 | const SessionReducer = (state = _nullUser, action) => {
10 | Object.freeze(state);
11 | switch(action.type) {
12 | case RECEIVE_CURRENT_USER:
13 | const currentUser = action.currentUser;
14 | return merge({}, _nullUser, {
15 | currentUser
16 | });
17 | case RECEIVE_ERRORS:
18 | const errors = action.errors;
19 | return merge({}, _nullUser, {
20 | errors
21 | });
22 | default:
23 | return state;
24 | }
25 | };
26 |
27 | export default SessionReducer;
28 |
--------------------------------------------------------------------------------
/frontend/reducers/stage_reducer.js:
--------------------------------------------------------------------------------
1 | import { UPDATE_STAGE } from '../actions/stage_actions';
2 |
3 | const initialState = {
4 | taskers_present: "",
5 |
6 | };
7 |
8 |
9 |
10 |
11 | const stageReducer = (state = {}, action) => {
12 | Object.freeze(state);
13 | switch(action.type) {
14 | case UPDATE_STAGE:
15 | const newStage = Object.merge({}, state, action.stage);
16 | return newStage;
17 | default:
18 | return state;
19 | }
20 | };
21 |
22 | export default stageReducer;
23 |
--------------------------------------------------------------------------------
/frontend/reducers/task_reducer.js:
--------------------------------------------------------------------------------
1 | import { RECEIVE_TASK, RECEIVE_TASKS, CLEAR_NEW_TASK } from '../actions/task_actions';
2 | import merge from 'lodash/merge';
3 |
4 | const tasksReducer = (state = {}, action) => {
5 | Object.freeze(state);
6 | switch(action.type) {
7 | case RECEIVE_TASKS:
8 | return action.tasks;
9 | case RECEIVE_TASK:
10 | const newTaskState = Object.merge({}, state, action.task);
11 | return newTaskState;
12 | default:
13 | return state;
14 | }
15 | };
16 |
17 | export default tasksReducer;
18 |
--------------------------------------------------------------------------------
/frontend/reducers/tasker_reducer.js:
--------------------------------------------------------------------------------
1 | import { RECEIVE_TASKERS, CLEAR_TASKERS } from '../actions/user_actions';
2 | import { setTaskers, clearTaskers } from '../components/forms/newTask/session_util';
3 | const initialState = {
4 | present: ""
5 | };
6 |
7 | const TaskersReducer = (state = initialState, action) => {
8 |
9 | Object.freeze(state);
10 | switch(action.type) {
11 | case RECEIVE_TASKERS:
12 | if(action.tasker_data.present === 'false') {
13 | return { present: action.tasker_data.present };
14 | } else {
15 | setTaskers(action.tasker_data.taskers);
16 | return action.tasker_data.taskers;
17 | }
18 | case CLEAR_TASKERS:
19 | clearTaskers();
20 | return initialState;
21 | default:
22 | return state;
23 | }
24 | };
25 |
26 | export default TaskersReducer;
27 |
--------------------------------------------------------------------------------
/frontend/store/store.js:
--------------------------------------------------------------------------------
1 | import rootReducer from '../reducers/root_reducer';
2 | import thunk from 'redux-thunk';
3 | import { createStore, applyMiddleware } from 'redux';
4 |
5 | const configureStore = (preloadedState = {}) => (
6 | createStore(
7 | rootReducer,
8 | preloadedState,
9 | applyMiddleware(thunk)
10 | )
11 | );
12 |
13 | export default configureStore;
14 |
--------------------------------------------------------------------------------
/frontend/util/api_util.js:
--------------------------------------------------------------------------------
1 | export const login = (user) => {
2 | return $.ajax({
3 | method: 'POST',
4 | url: '/api/session/',
5 | data: user
6 | });
7 | };
8 |
9 | export const logout = () => {
10 | return $.ajax({
11 | method: 'DELETE',
12 | url: '/api/session/'
13 | });
14 | };
15 |
16 | export const signup = (user) => {
17 | return $.ajax({
18 | method: 'POST',
19 | url: '/api/users',
20 | data: user
21 | });
22 | };
23 |
24 | export const edit = (user) => {
25 | return $.ajax({
26 | method: 'PATCH',
27 | url: `/api/users/${user.id}`,
28 | data: {user: user}
29 | });
30 | };
31 |
32 | export const categories = () => {
33 | return $.ajax({
34 | method: 'GET',
35 | url: '/api/categories'
36 | });
37 | };
38 |
39 | export const fetchCategory = (id) => {
40 | return $.ajax({
41 | method: 'GET',
42 | url: `/api/category/${id}`
43 | });
44 | };
45 |
46 | export const requestedTasks = () => {
47 | return $.ajax({
48 | method: 'GET',
49 | url: '/api/tasks'
50 | });
51 | };
52 |
53 | export const createTask = (task) => {
54 | return $.ajax({
55 | method: 'POST',
56 | url: '/api/tasks',
57 | data: { task }
58 | });
59 | };
60 |
61 | export const fetchTaskers = (category_id, locality) => {
62 |
63 | return $.ajax({
64 | method: 'GET',
65 | url: '/api/taskers',
66 | data: {
67 | category_id: category_id,
68 | locality: locality
69 | }
70 | });
71 | };
72 |
--------------------------------------------------------------------------------
/frontend/util/date_util.js:
--------------------------------------------------------------------------------
1 | export const generateDateString = (date) =>
2 | {
3 | let year = date.getFullYear();
4 | let month = (parseInt(date.getMonth()) + 1)
5 | if(month < 10) {
6 | month = month.toString();
7 | month = `0${month}`;
8 | }
9 | let day = date.getDate();
10 | if(day < 10) {
11 | day = day.toString();
12 | day = `0${day}`;
13 | }
14 |
15 | return `${year}-${month}-${day}`;
16 | };
17 |
--------------------------------------------------------------------------------
/frontend/util/form_util.jsx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/frontend/util/form_util.jsx
--------------------------------------------------------------------------------
/frontend/util/prop_util.js:
--------------------------------------------------------------------------------
1 | export const setStateForDifProps = (oldProp, newProp, keys) => {
2 | for (const i = 0; i < Object.keys(keys).length; i++) {
3 | let key = Object.keys(keys)[i];
4 | if(oldProp[key] !== newProp[key]) {
5 | this.setState({}
6 | }
7 | }
8 | Object.keys.forEach({
9 |
10 |
11 | });
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/frontend/util/sort_util.js:
--------------------------------------------------------------------------------
1 | export const generateSort = (direction, field) => {
2 | const compareTaskers = (obj1, obj2, field) => {
3 | if(obj1[`${field}`] > obj2[`${field}`]){
4 | return -1;
5 | } else if (obj1[`${field}`] === obj2[`${field}`]) {
6 | return 0;
7 | } else {
8 | return 1;
9 | }
10 | };
11 |
12 | if(direction === "asc"){
13 | return (tasker1, tasker2) => compareTaskers(tasker2, tasker1, field);
14 | } else {
15 | return (tasker1, tasker2) => compareTaskers(tasker1, tasker2, field);
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/lib/assets/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/lib/assets/.keep
--------------------------------------------------------------------------------
/lib/tasks/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/lib/tasks/.keep
--------------------------------------------------------------------------------
/log/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/log/.keep
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "classRabbit",
3 | "version": "1.0.0",
4 | "description": "This README would normally document whatever steps are necessary to get the application up and running.",
5 | "main": "index.js",
6 | "directories": {
7 | "doc": "docs",
8 | "test": "test"
9 | },
10 | "engines": {
11 | "node": "6.7.0",
12 | "npm": "3.10.7"
13 | },
14 | "scripts": {
15 | "test": "echo \"Error: no test specified\" && exit 1",
16 | "postinstall": "webpack"
17 | },
18 | "repository": {
19 | "type": "git",
20 | "url": "git+https://github.com/dplain90/classRabbit.git"
21 | },
22 | "keywords": [],
23 | "author": "",
24 | "license": "ISC",
25 | "bugs": {
26 | "url": "https://github.com/dplain90/classRabbit/issues"
27 | },
28 | "homepage": "https://github.com/dplain90/classRabbit#readme",
29 | "dependencies": {
30 | "babel-core": "^6.24.1",
31 | "babel-loader": "^6.4.1",
32 | "babel-preset-es2015": "^6.24.1",
33 | "babel-preset-react": "^6.24.1",
34 | "react": "^15.5.4",
35 | "react-dom": "^15.5.4",
36 | "react-redux": "^5.0.4",
37 | "react-router": "^3.0.5",
38 | "react-slick": "^0.14.11",
39 | "react-smooth-collapse": "^1.1.1",
40 | "redux": "^3.6.0",
41 | "redux-thunk": "^2.2.0",
42 | "webpack": "^2.4.1"
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/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/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/public/apple-touch-icon-precomposed.png
--------------------------------------------------------------------------------
/public/apple-touch-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/public/apple-touch-icon.png
--------------------------------------------------------------------------------
/public/assets/angel-list-icon-f69a49b38b337b46376ab9071b3812638e935ccc77e4d42bfe60bcd0ff5bb97c.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/public/assets/angel-list-icon-f69a49b38b337b46376ab9071b3812638e935ccc77e4d42bfe60bcd0ff5bb97c.png
--------------------------------------------------------------------------------
/public/assets/application-1329aa1b43f69eece5a3c1fe510776e0821aa21ec5303792db2b9c2f0d9e5ea7.js.gz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/public/assets/application-1329aa1b43f69eece5a3c1fe510776e0821aa21ec5303792db2b9c2f0d9e5ea7.js.gz
--------------------------------------------------------------------------------
/public/assets/application-16f9b15f3ce2510638f0c043c1701a3245e1d27c9a05c7e5f7c79013aabd227d.js.gz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/public/assets/application-16f9b15f3ce2510638f0c043c1701a3245e1d27c9a05c7e5f7c79013aabd227d.js.gz
--------------------------------------------------------------------------------
/public/assets/application-266a45f600ac94e48316b656ae7da095393f0676c5c9e9a7be88575a83a22f40.css.gz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/public/assets/application-266a45f600ac94e48316b656ae7da095393f0676c5c9e9a7be88575a83a22f40.css.gz
--------------------------------------------------------------------------------
/public/assets/application-5dc56f91dd3926dab5b27e876ec2b67cad9856d26e0052afdf554f0087823ff5.css.gz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/public/assets/application-5dc56f91dd3926dab5b27e876ec2b67cad9856d26e0052afdf554f0087823ff5.css.gz
--------------------------------------------------------------------------------
/public/assets/application-6c8096a5b2ef6ba164ba554b26c3d5fbe751cdc001476a2ecc55379293d71864.css.gz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/public/assets/application-6c8096a5b2ef6ba164ba554b26c3d5fbe751cdc001476a2ecc55379293d71864.css.gz
--------------------------------------------------------------------------------
/public/assets/application-adc8e30501b0ec675ce978cf204a9a228cfcf614c42c86c13b79dd53abf4aa10.css.gz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/public/assets/application-adc8e30501b0ec675ce978cf204a9a228cfcf614c42c86c13b79dd53abf4aa10.css.gz
--------------------------------------------------------------------------------
/public/assets/application-bf47448ae0701152f71c0c545e09e24d5cdb478e162f373f54b50f9e1c635bc2.js.gz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/public/assets/application-bf47448ae0701152f71c0c545e09e24d5cdb478e162f373f54b50f9e1c635bc2.js.gz
--------------------------------------------------------------------------------
/public/assets/application-c415be9a01beacaf38e2d3ed8c34fb541b3bfcbdb042cd8248873155abafcd41.js.gz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/public/assets/application-c415be9a01beacaf38e2d3ed8c34fb541b3bfcbdb042cd8248873155abafcd41.js.gz
--------------------------------------------------------------------------------
/public/assets/application-cab544a031436f8e3a76eadf850f78c7bd3899f46c28c6a2957413c9eb9f23d9.css.gz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/public/assets/application-cab544a031436f8e3a76eadf850f78c7bd3899f46c28c6a2957413c9eb9f23d9.css.gz
--------------------------------------------------------------------------------
/public/assets/application-e53c00f0227d0e650e45bb21545b1e7aa10af1cfbaac393f451775fc551227f7.css.gz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/public/assets/application-e53c00f0227d0e650e45bb21545b1e7aa10af1cfbaac393f451775fc551227f7.css.gz
--------------------------------------------------------------------------------
/public/assets/attendance-c21630bb325ed3f45edd939078c1a5a5a63b67b3c59d19ae286aeadd9525cf3f.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/public/assets/attendance-c21630bb325ed3f45edd939078c1a5a5a63b67b3c59d19ae286aeadd9525cf3f.png
--------------------------------------------------------------------------------
/public/assets/banner2-b87d22d18c76e2f251a09a63948893c28e7ba2a150728e5e81603ed65b56dda6.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/public/assets/banner2-b87d22d18c76e2f251a09a63948893c28e7ba2a150728e5e81603ed65b56dda6.jpg
--------------------------------------------------------------------------------
/public/assets/banner_image-040749868f0f75320378b4769bf5d56fe9fc534ff5f9bba3015962cd3eaa8e79.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/public/assets/banner_image-040749868f0f75320378b4769bf5d56fe9fc534ff5f9bba3015962cd3eaa8e79.jpg
--------------------------------------------------------------------------------
/public/assets/base/AvantGarde-a5e320e753bf733344275c365255c08179c514c481f04a9f0619b14b4a80efc1.OTF:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/public/assets/base/AvantGarde-a5e320e753bf733344275c365255c08179c514c481f04a9f0619b14b4a80efc1.OTF
--------------------------------------------------------------------------------
/public/assets/base/MyriadPro-It-ebce431f261a90c864e2ddeb5b40aafc622c88e2b0c0129aa6176fd1268d746b.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/public/assets/base/MyriadPro-It-ebce431f261a90c864e2ddeb5b40aafc622c88e2b0c0129aa6176fd1268d746b.ttf
--------------------------------------------------------------------------------
/public/assets/base/MyriadPro-It-ebce431f261a90c864e2ddeb5b40aafc622c88e2b0c0129aa6176fd1268d746b.ttf.gz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/public/assets/base/MyriadPro-It-ebce431f261a90c864e2ddeb5b40aafc622c88e2b0c0129aa6176fd1268d746b.ttf.gz
--------------------------------------------------------------------------------
/public/assets/base/avante_garde-f75b82705f752a4cbf64b87f458934ed4226f9999831e0d136a4ca48f6bac6c1.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/public/assets/base/avante_garde-f75b82705f752a4cbf64b87f458934ed4226f9999831e0d136a4ca48f6bac6c1.ttf
--------------------------------------------------------------------------------
/public/assets/base/avante_garde-f75b82705f752a4cbf64b87f458934ed4226f9999831e0d136a4ca48f6bac6c1.ttf.gz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/public/assets/base/avante_garde-f75b82705f752a4cbf64b87f458934ed4226f9999831e0d136a4ca48f6bac6c1.ttf.gz
--------------------------------------------------------------------------------
/public/assets/base/icomoon-0cf379d83f5f127519328d04b584947f01001cb0111bad35140b302cefa21bb1.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/public/assets/base/icomoon-0cf379d83f5f127519328d04b584947f01001cb0111bad35140b302cefa21bb1.woff
--------------------------------------------------------------------------------
/public/assets/base/icomoon-2d1273d2da2895aa086b0c1d3fede2b18ed238d5b66d63bf52f0374512c45374.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/public/assets/base/icomoon-2d1273d2da2895aa086b0c1d3fede2b18ed238d5b66d63bf52f0374512c45374.ttf
--------------------------------------------------------------------------------
/public/assets/base/icomoon-2d1273d2da2895aa086b0c1d3fede2b18ed238d5b66d63bf52f0374512c45374.ttf.gz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/public/assets/base/icomoon-2d1273d2da2895aa086b0c1d3fede2b18ed238d5b66d63bf52f0374512c45374.ttf.gz
--------------------------------------------------------------------------------
/public/assets/base/icomoon-92b12277f104fae86dae18d94337a36d6fe92f33bb5780bfb12a39b4c2a73a87.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/public/assets/base/icomoon-92b12277f104fae86dae18d94337a36d6fe92f33bb5780bfb12a39b4c2a73a87.eot
--------------------------------------------------------------------------------
/public/assets/base/icomoon-92b12277f104fae86dae18d94337a36d6fe92f33bb5780bfb12a39b4c2a73a87.eot.gz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/public/assets/base/icomoon-92b12277f104fae86dae18d94337a36d6fe92f33bb5780bfb12a39b4c2a73a87.eot.gz
--------------------------------------------------------------------------------
/public/assets/base/icomoon-b39188588dd12118ac755d6a22769ead6db0d28f704bd9618819ccb513dc5e69.svg.gz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/public/assets/base/icomoon-b39188588dd12118ac755d6a22769ead6db0d28f704bd9618819ccb513dc5e69.svg.gz
--------------------------------------------------------------------------------
/public/assets/base/proximanova-bold-webfont-a52d304a62b0e194a962f07be15426e76ed9be8e8a6bec3108242946fd96e8a0.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/public/assets/base/proximanova-bold-webfont-a52d304a62b0e194a962f07be15426e76ed9be8e8a6bec3108242946fd96e8a0.ttf
--------------------------------------------------------------------------------
/public/assets/base/proximanova-bold-webfont-a52d304a62b0e194a962f07be15426e76ed9be8e8a6bec3108242946fd96e8a0.ttf.gz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/public/assets/base/proximanova-bold-webfont-a52d304a62b0e194a962f07be15426e76ed9be8e8a6bec3108242946fd96e8a0.ttf.gz
--------------------------------------------------------------------------------
/public/assets/base/proximanova-light-webfont-70512d9977a8fcd4ba7c77417fb4984984197ca2857ef30206fbfe9dbec96965.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/public/assets/base/proximanova-light-webfont-70512d9977a8fcd4ba7c77417fb4984984197ca2857ef30206fbfe9dbec96965.ttf
--------------------------------------------------------------------------------
/public/assets/base/proximanova-light-webfont-70512d9977a8fcd4ba7c77417fb4984984197ca2857ef30206fbfe9dbec96965.ttf.gz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/public/assets/base/proximanova-light-webfont-70512d9977a8fcd4ba7c77417fb4984984197ca2857ef30206fbfe9dbec96965.ttf.gz
--------------------------------------------------------------------------------
/public/assets/base/proximanova-regular-webfont-2d77cd2df52cebe3d1eb8711a9ab9d0418fecdb343d3841cf9d4fee21e64e9b1.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/public/assets/base/proximanova-regular-webfont-2d77cd2df52cebe3d1eb8711a9ab9d0418fecdb343d3841cf9d4fee21e64e9b1.ttf
--------------------------------------------------------------------------------
/public/assets/base/proximanova-regular-webfont-2d77cd2df52cebe3d1eb8711a9ab9d0418fecdb343d3841cf9d4fee21e64e9b1.ttf.gz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/public/assets/base/proximanova-regular-webfont-2d77cd2df52cebe3d1eb8711a9ab9d0418fecdb343d3841cf9d4fee21e64e9b1.ttf.gz
--------------------------------------------------------------------------------
/public/assets/base/proximanova-semibold-webfont-d1f6f72f93791752f7deb94af920ef75b1759b46dd53c9d3b9a4b837d18ad835.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/public/assets/base/proximanova-semibold-webfont-d1f6f72f93791752f7deb94af920ef75b1759b46dd53c9d3b9a4b837d18ad835.ttf
--------------------------------------------------------------------------------
/public/assets/base/proximanova-semibold-webfont-d1f6f72f93791752f7deb94af920ef75b1759b46dd53c9d3b9a4b837d18ad835.ttf.gz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/public/assets/base/proximanova-semibold-webfont-d1f6f72f93791752f7deb94af920ef75b1759b46dd53c9d3b9a4b837d18ad835.ttf.gz
--------------------------------------------------------------------------------
/public/assets/base/proximanovat-thin-webfont-e637d92c95e7afe0c243b9c00b83c1e64b7743fd9eb0657379a593b9ab7cdeb4.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/public/assets/base/proximanovat-thin-webfont-e637d92c95e7afe0c243b9c00b83c1e64b7743fd9eb0657379a593b9ab7cdeb4.ttf
--------------------------------------------------------------------------------
/public/assets/base/proximanovat-thin-webfont-e637d92c95e7afe0c243b9c00b83c1e64b7743fd9eb0657379a593b9ab7cdeb4.ttf.gz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/public/assets/base/proximanovat-thin-webfont-e637d92c95e7afe0c243b9c00b83c1e64b7743fd9eb0657379a593b9ab7cdeb4.ttf.gz
--------------------------------------------------------------------------------
/public/assets/bed-25362534282e9e8196e8469af71aaea209251f38ab36f813dbc788a6b2c5cc09.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/public/assets/bed-25362534282e9e8196e8469af71aaea209251f38ab36f813dbc788a6b2c5cc09.jpg
--------------------------------------------------------------------------------
/public/assets/chairs-c045c090bb79f7d09f616456bc2252eb4dce55752e7ad4d0e4b74a0391a697c2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/public/assets/chairs-c045c090bb79f7d09f616456bc2252eb4dce55752e7ad4d0e4b74a0391a697c2.jpg
--------------------------------------------------------------------------------
/public/assets/classrabbit-02ed074774f1bbc382ca34b94d44ebf0e1e752281925a013dfe7791f2b40e037.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/public/assets/classrabbit-02ed074774f1bbc382ca34b94d44ebf0e1e752281925a013dfe7791f2b40e037.png
--------------------------------------------------------------------------------
/public/assets/cleaning-34a6f89f4f0c2f141151d75205cc757b62a00623e2bc6f8a4f618aaf427fe099.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/public/assets/cleaning-34a6f89f4f0c2f141151d75205cc757b62a00623e2bc6f8a4f618aaf427fe099.jpg
--------------------------------------------------------------------------------
/public/assets/couch-w-pillow-0aee74a126ac3831b7285cf9f223dcbe95147dfe01e8f53ff737cf0b26decbbf.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/public/assets/couch-w-pillow-0aee74a126ac3831b7285cf9f223dcbe95147dfe01e8f53ff737cf0b26decbbf.jpg
--------------------------------------------------------------------------------
/public/assets/default_avatar-6c22db894f6a1d7a84717f2c80c30210a42cb94da932f661eb0b060d4d8a2f0e.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/public/assets/default_avatar-6c22db894f6a1d7a84717f2c80c30210a42cb94da932f661eb0b060d4d8a2f0e.jpg
--------------------------------------------------------------------------------
/public/assets/favicon-e17908cc156f99510192d87dfc461b1b9898b6559a47be4741bb17dda26c83a7.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/public/assets/favicon-e17908cc156f99510192d87dfc461b1b9898b6559a47be4741bb17dda26c83a7.ico
--------------------------------------------------------------------------------
/public/assets/favicon-e17908cc156f99510192d87dfc461b1b9898b6559a47be4741bb17dda26c83a7.ico.gz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/public/assets/favicon-e17908cc156f99510192d87dfc461b1b9898b6559a47be4741bb17dda26c83a7.ico.gz
--------------------------------------------------------------------------------
/public/assets/final_taskrabbit_logo-a88d820c4047c02c82df84cc7d67948f6ac7d7004f48202250fe3b7efdc3db34.svg.gz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/public/assets/final_taskrabbit_logo-a88d820c4047c02c82df84cc7d67948f6ac7d7004f48202250fe3b7efdc3db34.svg.gz
--------------------------------------------------------------------------------
/public/assets/github-icon-final-860f6e03a20a87dfdc2778e5c2521e68417f3cd0e2d678676d1d6088a385363d.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/public/assets/github-icon-final-860f6e03a20a87dfdc2778e5c2521e68417f3cd0e2d678676d1d6088a385363d.png
--------------------------------------------------------------------------------
/public/assets/hard_drive-90df10939d245f25cd4907ed2dd95f07e17462127f4acfb56424b4ab5cb758bc.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/public/assets/hard_drive-90df10939d245f25cd4907ed2dd95f07e17462127f4acfb56424b4ab5cb758bc.jpg
--------------------------------------------------------------------------------
/public/assets/home_improvements-8265e8d01dc48cbdfa4a01097be7c746eed5cee5e4434f98f709ceffe287622a.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/public/assets/home_improvements-8265e8d01dc48cbdfa4a01097be7c746eed5cee5e4434f98f709ceffe287622a.jpg
--------------------------------------------------------------------------------
/public/assets/linkedin-icon-final-4b3fe8eaa84961dccfb421d58d0278bd2a6792f23b78fb5a7cefad96e0beda64.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/public/assets/linkedin-icon-final-4b3fe8eaa84961dccfb421d58d0278bd2a6792f23b78fb5a7cefad96e0beda64.png
--------------------------------------------------------------------------------
/public/assets/logo-85ee3f8a9adfc9d00a69681f25043cafcd5e44bebb95c80ad7f32f93dd161924.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/public/assets/logo-85ee3f8a9adfc9d00a69681f25043cafcd5e44bebb95c80ad7f32f93dd161924.png
--------------------------------------------------------------------------------
/public/assets/microcitybutton-664b09a120c3f417e85e2870b2cb5a5368472d6cb09b44ab73c8b2e0b6c09700.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/public/assets/microcitybutton-664b09a120c3f417e85e2870b2cb5a5368472d6cb09b44ab73c8b2e0b6c09700.png
--------------------------------------------------------------------------------
/public/assets/microcitybutton2-b601b2cfa57a66885c293b95d6f65bd1fe9c9832520833b1785a2344e518a38a.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/public/assets/microcitybutton2-b601b2cfa57a66885c293b95d6f65bd1fe9c9832520833b1785a2344e518a38a.png
--------------------------------------------------------------------------------
/public/assets/modal-background-0cd6fcda12129ba567a23982a65fa170eaa69feb9cfefb0bbf160ff3e8f77a14.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/public/assets/modal-background-0cd6fcda12129ba567a23982a65fa170eaa69feb9cfefb0bbf160ff3e8f77a14.jpg
--------------------------------------------------------------------------------
/public/assets/ordering-7c06c727081ee88d0fba8c7e82b72d967b50d3a5bfe13e90ef35020588683238.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/public/assets/ordering-7c06c727081ee88d0fba8c7e82b72d967b50d3a5bfe13e90ef35020588683238.jpg
--------------------------------------------------------------------------------
/public/assets/plainChessButton-51cda93acaa1861495e091c0f9001f653cf9a3479d7dd185df3c435a76ee5d91.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/public/assets/plainChessButton-51cda93acaa1861495e091c0f9001f653cf9a3479d7dd185df3c435a76ee5d91.png
--------------------------------------------------------------------------------
/public/assets/printing-f33ce00cc4dccda010d3c2be118bf2be5545368062598c9b785de6da7e3ada3e.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/public/assets/printing-f33ce00cc4dccda010d3c2be118bf2be5545368062598c9b785de6da7e3ada3e.jpg
--------------------------------------------------------------------------------
/public/assets/profile_pictures/default_avatar-6c22db894f6a1d7a84717f2c80c30210a42cb94da932f661eb0b060d4d8a2f0e.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/public/assets/profile_pictures/default_avatar-6c22db894f6a1d7a84717f2c80c30210a42cb94da932f661eb0b060d4d8a2f0e.jpg
--------------------------------------------------------------------------------
/public/assets/profile_pictures/regular_users/prof_pic1-78462e5e4ed8ff509571d2692a25b2e11c36a97f3fb84c33c26b9fbb27299f16.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/public/assets/profile_pictures/regular_users/prof_pic1-78462e5e4ed8ff509571d2692a25b2e11c36a97f3fb84c33c26b9fbb27299f16.jpg
--------------------------------------------------------------------------------
/public/assets/profile_pictures/regular_users/prof_pic2-8a569050c53b5505cd1cf810ea73527daf9bc663debeed40457d8d53fe6aa715.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/public/assets/profile_pictures/regular_users/prof_pic2-8a569050c53b5505cd1cf810ea73527daf9bc663debeed40457d8d53fe6aa715.jpg
--------------------------------------------------------------------------------
/public/assets/profile_pictures/regular_users/prof_pic3-86caa139989db187440c0198c387ef5ac226d8846757f92d23883990ad92a20e.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/public/assets/profile_pictures/regular_users/prof_pic3-86caa139989db187440c0198c387ef5ac226d8846757f92d23883990ad92a20e.jpg
--------------------------------------------------------------------------------
/public/assets/profile_pictures/regular_users/prof_pic4-c25fcf22cc141f8a85d686aa37f776896c5c90709d0abac520a9efadd3e5600b.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/public/assets/profile_pictures/regular_users/prof_pic4-c25fcf22cc141f8a85d686aa37f776896c5c90709d0abac520a9efadd3e5600b.png
--------------------------------------------------------------------------------
/public/assets/profile_pictures/regular_users/prof_pic5-d7d13d287a8bc57a0c74721eaad11a95bc6c3dd8a77bc705e615f933a5833811.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/public/assets/profile_pictures/regular_users/prof_pic5-d7d13d287a8bc57a0c74721eaad11a95bc6c3dd8a77bc705e615f933a5833811.jpg
--------------------------------------------------------------------------------
/public/assets/profile_pictures/taskers/tasker1-21aacd71fa0e89b1e00e1b62ed6fbd75da4092202f08c798aae805b0f7620028.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/public/assets/profile_pictures/taskers/tasker1-21aacd71fa0e89b1e00e1b62ed6fbd75da4092202f08c798aae805b0f7620028.jpg
--------------------------------------------------------------------------------
/public/assets/profile_pictures/taskers/tasker1-9dbfdf42a5e1f9391e6f1e72c8bb23aada746bbc7db9f084fa5af4888d59623d.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/public/assets/profile_pictures/taskers/tasker1-9dbfdf42a5e1f9391e6f1e72c8bb23aada746bbc7db9f084fa5af4888d59623d.jpg
--------------------------------------------------------------------------------
/public/assets/profile_pictures/taskers/tasker2-52cdf0788e1d5158ae2c6d6285477bd6d2709ff435e09f397d902534d8c98f76.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/public/assets/profile_pictures/taskers/tasker2-52cdf0788e1d5158ae2c6d6285477bd6d2709ff435e09f397d902534d8c98f76.jpg
--------------------------------------------------------------------------------
/public/assets/profile_pictures/taskers/tasker3-06dcf2bee12a01be02153747190a3436150c12e48e2448d5b8783efff8705c88.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/public/assets/profile_pictures/taskers/tasker3-06dcf2bee12a01be02153747190a3436150c12e48e2448d5b8783efff8705c88.png
--------------------------------------------------------------------------------
/public/assets/profile_pictures/taskers/tasker3-e819c0ab4e71a806bb36cab558e637ffaba395c8ff758651318eb7cd0b520c10.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/public/assets/profile_pictures/taskers/tasker3-e819c0ab4e71a806bb36cab558e637ffaba395c8ff758651318eb7cd0b520c10.jpg
--------------------------------------------------------------------------------
/public/assets/profile_pictures/taskers/tasker4-0e3d8796dfb63d0d97eaebbe9fe1297d58111321e49cdb568827ec2586e45fba.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/public/assets/profile_pictures/taskers/tasker4-0e3d8796dfb63d0d97eaebbe9fe1297d58111321e49cdb568827ec2586e45fba.jpg
--------------------------------------------------------------------------------
/public/assets/profile_pictures/taskers/tasker4-4e5cbdb9da9995cfe9c6ca51db084cb627b0c090b1cab71d370f89a56d8e2c23.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/public/assets/profile_pictures/taskers/tasker4-4e5cbdb9da9995cfe9c6ca51db084cb627b0c090b1cab71d370f89a56d8e2c23.jpg
--------------------------------------------------------------------------------
/public/assets/profile_pictures/taskers/tasker5-b094e663e8eae460230953b999525ef23a1fda9350ee410a5822a0f2ae730399.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/public/assets/profile_pictures/taskers/tasker5-b094e663e8eae460230953b999525ef23a1fda9350ee410a5822a0f2ae730399.jpg
--------------------------------------------------------------------------------
/public/assets/profile_pictures/taskers/tasker_prof1-b687255672fc7f94b8462101660bbb4d407f15502e7475a248f5166f80a144a0.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/public/assets/profile_pictures/taskers/tasker_prof1-b687255672fc7f94b8462101660bbb4d407f15502e7475a248f5166f80a144a0.jpg
--------------------------------------------------------------------------------
/public/assets/profile_pictures/taskers/tasker_prof2-ee9047f617fc7868d945c98a94392aab2a1d8f08210a42cd6403421500309129.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/public/assets/profile_pictures/taskers/tasker_prof2-ee9047f617fc7868d945c98a94392aab2a1d8f08210a42cd6403421500309129.jpg
--------------------------------------------------------------------------------
/public/assets/profile_pictures/taskers/tasker_prof3-0889fdd6464b10021aceb289b3d2f6e10554c2367d81f999ff3d1d7367b7108c.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/public/assets/profile_pictures/taskers/tasker_prof3-0889fdd6464b10021aceb289b3d2f6e10554c2367d81f999ff3d1d7367b7108c.jpg
--------------------------------------------------------------------------------
/public/assets/profile_pictures/taskers/tasker_prof4-8b43deb7f6662b9e60939db99feaf52f104d639074f9cae0653c52fe424bc01c.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/public/assets/profile_pictures/taskers/tasker_prof4-8b43deb7f6662b9e60939db99feaf52f104d639074f9cae0653c52fe424bc01c.jpg
--------------------------------------------------------------------------------
/public/assets/repairs-bfd09b976f6e2583a6a196cec72a4173ec8b896dbb845b1b9675a69566db5ae1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/public/assets/repairs-bfd09b976f6e2583a6a196cec72a4173ec8b896dbb845b1b9675a69566db5ae1.jpg
--------------------------------------------------------------------------------
/public/assets/splashLink_photo_med-95370e9768636accf882bd5ef1d3fdb14d1c55c24c18049f5a71858eec078407.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/public/assets/splashLink_photo_med-95370e9768636accf882bd5ef1d3fdb14d1c55c24c18049f5a71858eec078407.jpg
--------------------------------------------------------------------------------
/public/assets/splash_background-aca190b62d2f3c58956f06bcdb4e2727930b4b2397958d0bc8a7eed9575a198b.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/public/assets/splash_background-aca190b62d2f3c58956f06bcdb4e2727930b4b2397958d0bc8a7eed9575a198b.png
--------------------------------------------------------------------------------
/public/assets/splash_background_blur-a9a8cb07010fd928b99a2c6e50453a45257edaa7115d4bea89b5da2e8c154e21.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/public/assets/splash_background_blur-a9a8cb07010fd928b99a2c6e50453a45257edaa7115d4bea89b5da2e8c154e21.png
--------------------------------------------------------------------------------
/public/assets/teaching_assistant-37ec433387c63f751acc3c25eeeb1def70090a03e974c42f44eb4079076aee7b.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/public/assets/teaching_assistant-37ec433387c63f751acc3c25eeeb1def70090a03e974c42f44eb4079076aee7b.jpg
--------------------------------------------------------------------------------
/public/assets/trust_badge-39be339305b1813c6086fba03d2e8897a9b8ee2869233d1cd83f79fa20a2c1b8.svg.gz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/public/assets/trust_badge-39be339305b1813c6086fba03d2e8897a9b8ee2869233d1cd83f79fa20a2c1b8.svg.gz
--------------------------------------------------------------------------------
/public/assets/tv-011cd9df181838237a8db3904ce637460ea36593ca1c4f3218524fa3bf4b4021.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/public/assets/tv-011cd9df181838237a8db3904ce637460ea36593ca1c4f3218524fa3bf4b4021.jpg
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/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 | #
3 | # To ban all spiders from the entire site uncomment the next two lines:
4 | # User-agent: *
5 | # Disallow: /
6 |
--------------------------------------------------------------------------------
/test/controllers/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/test/controllers/.keep
--------------------------------------------------------------------------------
/test/fixtures/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/test/fixtures/.keep
--------------------------------------------------------------------------------
/test/fixtures/files/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/test/fixtures/files/.keep
--------------------------------------------------------------------------------
/test/fixtures/users.yml:
--------------------------------------------------------------------------------
1 | # == Schema Information
2 | #
3 | # Table name: users
4 | #
5 | # id :integer not null, primary key
6 | # fname :string not null
7 | # lname :string not null
8 | # email :string not null
9 | # password_digest :string not null
10 | # session_token :string not null
11 | # phone_number :string not null
12 | # zip_code :string not null
13 | # locality :string not null
14 | # tasker :boolean default("true"), not null
15 | # created_at :datetime not null
16 | # updated_at :datetime not null
17 | # avatar_file_name :string
18 | # avatar_content_type :string
19 | # avatar_file_size :integer
20 | # avatar_updated_at :datetime
21 | #
22 |
23 | # Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html
24 |
25 | # This model initially had no columns defined. If you add columns to the
26 | # model remove the '{}' from the fixture names and add the columns immediately
27 | # below each fixture, per the syntax in the comments below
28 | #
29 | one: {}
30 | # column: value
31 | #
32 | two: {}
33 | # column: value
34 |
--------------------------------------------------------------------------------
/test/helpers/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/test/helpers/.keep
--------------------------------------------------------------------------------
/test/integration/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/test/integration/.keep
--------------------------------------------------------------------------------
/test/mailers/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/test/mailers/.keep
--------------------------------------------------------------------------------
/test/models/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/test/models/.keep
--------------------------------------------------------------------------------
/test/models/user_test.rb:
--------------------------------------------------------------------------------
1 | # == Schema Information
2 | #
3 | # Table name: users
4 | #
5 | # id :integer not null, primary key
6 | # fname :string not null
7 | # lname :string not null
8 | # email :string not null
9 | # password_digest :string not null
10 | # session_token :string not null
11 | # phone_number :string not null
12 | # zip_code :string not null
13 | # locality :string not null
14 | # tasker :boolean default("true"), not null
15 | # created_at :datetime not null
16 | # updated_at :datetime not null
17 | # avatar_file_name :string
18 | # avatar_content_type :string
19 | # avatar_file_size :integer
20 | # avatar_updated_at :datetime
21 | #
22 |
23 | require 'test_helper'
24 |
25 | class UserTest < ActiveSupport::TestCase
26 | # test "the truth" do
27 | # assert true
28 | # end
29 | end
30 |
--------------------------------------------------------------------------------
/test/test_helper.rb:
--------------------------------------------------------------------------------
1 | ENV['RAILS_ENV'] ||= 'test'
2 | require File.expand_path('../../config/environment', __FILE__)
3 | require 'rails/test_help'
4 |
5 | class ActiveSupport::TestCase
6 | # Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order.
7 | fixtures :all
8 |
9 | # Add more helper methods to be used by all tests here...
10 | end
11 |
--------------------------------------------------------------------------------
/tmp/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/tmp/.keep
--------------------------------------------------------------------------------
/vendor/assets/javascripts/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/vendor/assets/javascripts/.keep
--------------------------------------------------------------------------------
/vendor/assets/stylesheets/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dplain90/classRabbit/d2b26d421b91eb3e1cb9c6eae64ebeeda7c0dc88/vendor/assets/stylesheets/.keep
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 |
3 | module.exports = {
4 | context: __dirname,
5 | entry: './frontend/index.jsx',
6 | output: {
7 | path: path.resolve(__dirname, 'app', 'assets', 'javascripts'),
8 | filename: 'bundle.js'
9 | },
10 | resolve: {
11 | extensions: ['.js', '.jsx', '*']
12 | },
13 | module: {
14 | loaders: [
15 | {
16 | test: /\.jsx?$/,
17 | exclude: /(node_modules|bower_components)/,
18 | loader: 'babel-loader',
19 | query: {
20 | presets: ['react', 'es2015']
21 | }
22 | }
23 | ]
24 | },
25 | devtool: 'source-maps'
26 | };
27 |
--------------------------------------------------------------------------------