├── .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 |
15 |
16 | 22 |
23 | 24 | 25 | 26 |
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 |
66 | Details 67 |
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 |
22 | { allTasks } 23 |
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 |
15 | 21 | 22 | 25 | 26 | 29 |
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 |
17 |
    18 |
  • 19 | 20 |
    21 | {fname} {lname} 22 |
    23 |
  • 24 |
  • 25 | 26 |
    27 | {email} 28 |
    29 |
  • 30 |
  • 31 | 32 |
    33 | {phone_number} 34 |
    35 |
  • 36 |
  • 37 | 38 |
    39 | {zip_code} 40 |
    41 |
  • 42 |
  • 43 | 44 |
  • 45 | 46 | 47 |
48 | 49 |
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 |
63 |
    64 |
  • 65 | { fnameInput } 66 | { lnameInput } 67 |
  • 68 |
  • 69 | { emailAddressInput } 70 |
  • 71 |
  • 72 | { phoneInput } 73 |
  • 74 |
  • 75 | { zipCodeInput } 76 |
  • 77 |
78 | 79 |
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 |
14 | 15 | 16 | 17 | 18 | 19 | 20 |
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 | --------------------------------------------------------------------------------