diff --git a/.circleci/config.yml b/.circleci/config.yml index a5a599916a..810c4633bd 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -231,6 +231,7 @@ workflows: branches: only: - hot-fix + - integration-v5-develop # This is alternate dev env for parallel testing - "build-test": context : org-global @@ -252,6 +253,7 @@ workflows: branches: only: - hot-fix + - integration-v5-develop # This is stage env for production QA releases - "build-prod-staging": context : org-global diff --git a/.eslintrc b/.eslintrc index ddc5f09737..0636c3dfd6 100644 --- a/.eslintrc +++ b/.eslintrc @@ -2,7 +2,8 @@ "extends": "./node_modules/topcoder-react-utils/config/eslint/default.json", "rules": { "jsx-a11y/anchor-is-valid": false, - "import/no-cycle": [2, { "maxDepth": 1 }] + "import/no-cycle": [2, { "maxDepth": 1 }], + "react/forbid-prop-types": false }, "env": { "browser": true diff --git a/__tests__/shared/components/ChallengeTile/__mocks__/design.json b/__tests__/shared/components/ChallengeTile/__mocks__/design.json index 9bf42f544c..eece77716d 100644 --- a/__tests__/shared/components/ChallengeTile/__mocks__/design.json +++ b/__tests__/shared/components/ChallengeTile/__mocks__/design.json @@ -15,10 +15,11 @@ "technologies": "", "status": "COMPLETED", "legacy": { - "track": "DESIGN", "forumId": 599349 }, - "subTrack": "LOGO_DESIGN", + "track": "Design", + "type": "Challenge", + "tags": "Logo Design", "name": "Sunshot - MapMySolar - SunGiver - Brand Concept Logo Design Challenge", "reviewType": "INTERNAL", "id": 30051608, @@ -320,10 +321,11 @@ "technologies": "", "status": "COMPLETED", "legacy": { - "track": "DESIGN", "forumId": 598066 }, - "subTrack": "LOGO_DESIGN", + "track": "Design", + "type": "Challenge", + "tags": ["Logo Design"], "name": "2016 Topcoder Open Logo Design Challenge", "reviewType": "INTERNAL", "id": 30051059, @@ -532,10 +534,11 @@ "technologies": "", "status": "COMPLETED", "legacy": { - "track": "DESIGN", "forumId": 596557 }, - "subTrack": "LOGO_DESIGN", + "track": "Design", + "type": "Challenge", + "tags": "Logo Design", "name": "ACME Logos Design Challenge", "reviewType": "INTERNAL", "id": 30050375, diff --git a/__tests__/shared/components/ChallengeTile/__mocks__/develop.json b/__tests__/shared/components/ChallengeTile/__mocks__/develop.json index ec6b731307..9a48f9f5fb 100644 --- a/__tests__/shared/components/ChallengeTile/__mocks__/develop.json +++ b/__tests__/shared/components/ChallengeTile/__mocks__/develop.json @@ -22,10 +22,10 @@ "technologies": "CSS, HTML, JavaScript", "status": "COMPLETED", "legacy": { - "track": "DEVELOP", "forumId": 39153 }, - "subTrack": "FIRST_2_FINISH", + "track": "Development", + "type": "First2Finish", "name": "$100 Eaton PX 2.0 Petting Zoo - MDC Web Enhancement F2F Challenge", "reviewType": "INTERNAL", "id": 30060905, @@ -165,10 +165,10 @@ "technologies": "ReactJS", "status": "COMPLETED", "legacy": { - "track": "DEVELOP", "forumId": 39151 }, - "subTrack": "FIRST_2_FINISH", + "track": "Development", + "type": "First2Finish", "name": "$100 Eaton PX 2.0 Petting Zoo - ReactJS Enhancement F2F Challenge", "reviewType": "INTERNAL", "id": 30060903, @@ -323,10 +323,10 @@ "technologies": "Angular 2+, Express, JSON, Node.js", "status": "COMPLETED", "legacy": { - "track": "DEVELOP", "forumId": 38951 }, - "subTrack": "FIRST_2_FINISH", + "track": "Development", + "type": "First2Finish", "name": "$500 BG800 Online Course Mock Rest API F2F Challenge", "reviewType": "INTERNAL", "id": 30060687, @@ -630,11 +630,11 @@ "updatedBy": "22841596", "technologies": "JavaScript, ReactJS", "status": "COMPLETED", - "legacy": { - "track": "DEVELOP", + "legacy": { "forumId": 38702 }, - "subTrack": "FIRST_2_FINISH", + "track": "Development", + "type": "First2Finish", "name": "John Hancock - Giving Tuesday - General image handling", "reviewType": "INTERNAL", "id": 30060425, diff --git a/__tests__/shared/components/ChallengeTile/__mocks__/marathon.json b/__tests__/shared/components/ChallengeTile/__mocks__/marathon.json index a6d183de7c..2bc7157730 100644 --- a/__tests__/shared/components/ChallengeTile/__mocks__/marathon.json +++ b/__tests__/shared/components/ChallengeTile/__mocks__/marathon.json @@ -1,14 +1,12 @@ [{ "id": 15404, "name": "2018 TCO Marathon", - "type": "mmatches", "status": "PAST", "startDate": "2018-05-02T23:58:00.000Z", "endDate": "2018-05-02T23:58:00.000Z", - "legacy": { - "track": "DATA_SCIENCE" - }, - "subTrack": "MARATHON_MATCH", + "track": "Data Science", + "type": "Challenge", + "tags": ["Marathon Match"], "numOfRegistrants": null, "userIds": [141650, 158782, 276230, 282718, 283329, 7213681, 7359397, 7394165, 7442498, 7461533, 7465964, 7502813, 8366961, 8436045, 10233638, 10233638, 10467320, 10544397, 10597114, 10600282, 11854576, 13274356, 13298470, 14773682, 14883513, 14927744, 14991227, 15050434, 15118607, 16017427, 19740398, 20283608, 20315020, 20539063, 20783604, 20994662, 21114351, 21159810, 21179827, 21239511, 21688563, 21918101, 22020968, 22263204, 22389733, 22401534, 22627322, 22628625, 22629065, 22630490, 22638533, 22651906, 22653042, 22653720, 22653739, 22654575, 22656451, 22657201, 22657314, 22658052, 22661247, 22663117, 22663117, 22663924, 22671296, 22671296, 22671337, 22672408, 22674904, 22678508, 22680214, 22682274, 22682865, 22686512, 22688672, 22689976, 22692969, 22694931, 22697551, 22697669, 22704094, 22707222, 22718833, 22718910, 22721705, 22724258, 22727735, 22729239, 22734926, 22739971, 22741614, 22743661, 22744169, 22744421, 22747080, 22748044, 22753197, 22754284, 22756524, 22763515, 22768223, 22769598, 22769901, 22774534, 22774825, 22776482, 22779022, 22781646, 22781940, 22786326, 22794555, 22821941, 22825384, 22825875, 22826091, 22826139, 22826853, 22827765, 22828541, 22828546, 22829913, 22833363, 22843425, 22846688, 22850782, 22856251, 22858981, 22860336, 22860886, 22864722, 22868771, 22871352, 22873934, 22876363, 22881459, 22881735, 22897216, 22898655, 22906337, 22906557, 22906664, 22907549, 22909326, 22912209, 22912366, 22914184, 22919719, 22921277, 22923054, 22923054, 22924522, 22926652, 22929867, 22931891, 22932516, 23007886, 23008568, 23009812, 23015069, 23016887, 23018971, 23022695, 23026506, 23027339, 23040369, 23042482, 23042826, 23043484, 23044638, 23057573, 23057753, 23057905, 23069397, 23069974, 23070173, 23073768, 23073805, 23078492, 23080863, 23088109, 23088634, 23091447, 23092404, 23098513, 23100980, 23104345, 23104569, 23104569, 23115876, 23122212, 23127980, 23128010, 23128049, 23128490, 23128776, 23134176, 23141252, 23145211, 23145682, 23147616, 23149662, 23158804, 23161183, 23169412, 23170396, 23171633, 23177471, 23193535, 23264897, 23264897, 23285007, 23285054, 23285989, 23286857, 23289980, 23289980, 23292260, 23305127, 23308488, 23309818, 23309825, 23310707, 23323058, 23332062, 40005002, 40007407, 40007407, 40007844, 40014801, 40020552, 40022736, 40022736, 40027160, 40036552, 40038456, 40040728, 40050596, 40066523, 40082862, 40086753, 40094143, 40099108, 40106381, 40114709, 40116774, 40120624, 40130436, 40133770, 40133915, 40136338, 40140108, 40185279, 40188699, 40191001, 40196465, 40197594, 40215674, 40220230, 40236037, 40246974, 40247232, 40257176, 40259383, 40260799, 40266935, 40270737, 40270737, 40274368, 40293157, 40303624, 40309917, 40315743, 40319654, 40333188, 40336669, 40339779, 40347577, 40348876, 40350250, 40358649, 40361537, 40372812, 40392652, 40393775, 40396340, 40401694, 40402465, 40412809, 40433686, 40435654, 40443608, 40444244, 40446059, 40468706, 40480823, 40490675, 40496834, 40496834, 40502666, 40503423, 40505498, 40511723, 40513494, 40521665, 40523623, 40533186, 40543286, 40551842, 40554284, 40558626, 40560077, 40560115, 40562017, 40564389, 40572694, 40576855, 40576855, 40584681, 40586177, 40589817, 40589976, 40590641, 40594497, 40596982, 40596988, 40599327, 40600453, 40600514, 40618250, 40620991, 40621505, 40622191, 40624308, 40624612, 40630337, 40634796, 40638118, 40640695, 40640709, 40645709, 40646798, 40648689, 40649399, 40650540, 40651481, 40651481, 40652591, 40653455, 40655289, 40661549, 40667067, 40668009, 40675162, 40677436, 40678596, 40683329, 40684088, 40685467, 40686365, 40687942, 40690174, 40694576, 40705298, 40708164, 40708275, 40712448, 40714074, 40714397, 40715005, 40716035, 40716035, 40721133, 40723831, 40725891, 40726067, 40727059, 40734958, 40734958, 40738694, 40741634, 40742742, 40743704, 40744195, 40744262, 40745265, 40746165, 40746480, 40747463, 40749658, 40749849, 40750013, 40750028, 40750524, 40750715, 40751274, 40751284, 40751286, 40751290, 40752373, 40752902, 40752954, 40753004, 40753014, 40753051, 40753238, 40753292, 40753317, 40753398, 40753443, 40753452, 40753455, 40753666, 40753750, 40753792, 40753803, 40753978, 40754052, 40754086, 40754732, 40754772, 40754801, 40754967], "handles": null, @@ -41,14 +39,12 @@ }, { "id": 15207, "name": "2017 TCO Marathon", - "type": "mmatches", "status": "PAST", "startDate": "2017-04-12T16:36:00.000Z", "endDate": "2017-04-12T16:36:00.000Z", - "legacy": { - "track": "DATA_SCIENCE" - }, - "subTrack": "MARATHON_MATCH", + "track": "Data Science", + "type": "Challenge", + "tags": ["Marathon Match"], "numOfRegistrants": null, "userIds": [141650, 158782, 262598, 276230, 278425, 279876, 282718, 282718, 288302, 301395, 7213681, 7359397, 7390467, 7394165, 7442498, 7461533, 7465964, 7527926, 8366961, 8369898, 8400878, 8400878, 8436045, 8527113, 10278300, 10544397, 10597114, 10600282, 11789293, 13274356, 13274356, 13298470, 13365783, 14821847, 14881583, 14883513, 14927744, 14991227, 15580072, 15635590, 15781032, 15896190, 16017427, 19740398, 20315020, 20539063, 20799813, 20994662, 21114351, 21159810, 21162075, 21323186, 21500759, 21595895, 21688563, 21756423, 21990198, 22000198, 22020968, 22096856, 22255814, 22263204, 22628625, 22628772, 22629065, 22629850, 22644845, 22650894, 22651620, 22651906, 22652963, 22653042, 22653720, 22653739, 22654615, 22655052, 22657314, 22659807, 22661247, 22663924, 22671337, 22671446, 22672082, 22673613, 22674904, 22674904, 22675075, 22675075, 22680214, 22680376, 22682274, 22686050, 22686590, 22688641, 22688672, 22688964, 22689976, 22692760, 22692969, 22695559, 22696883, 22697551, 22697599, 22697669, 22697669, 22704094, 22705227, 22707497, 22708888, 22714779, 22718833, 22718910, 22718910, 22719721, 22727735, 22729239, 22730083, 22734926, 22736823, 22736823, 22738588, 22740367, 22740882, 22740882, 22741553, 22741614, 22743010, 22743661, 22744169, 22744390, 22744421, 22745629, 22745629, 22745897, 22748044, 22750409, 22751549, 22753458, 22758275, 22768223, 22768760, 22768760, 22774059, 22774534, 22776202, 22779022, 22780674, 22781250, 22781646, 22825496, 22826277, 22826721, 22827765, 22827765, 22827955, 22832123, 22832491, 22836242, 22836556, 22838816, 22846688, 22848598, 22850782, 22852089, 22852762, 22858920, 22859100, 22860336, 22861807, 22863733, 22864251, 22868476, 22868771, 22868771, 22871352, 22873934, 22875240, 22880808, 22881961, 22886772, 22888586, 22895368, 22897296, 22898655, 22901426, 22904503, 22905515, 22906337, 22906557, 22906664, 22910325, 22912209, 22912366, 22912545, 22914235, 22921568, 22923054, 22923054, 22923055, 22924522, 22926186, 22926652, 22929407, 22931372, 22931612, 22931891, 22933869, 23002583, 23004373, 23005191, 23012810, 23014542, 23016887, 23018456, 23019224, 23026219, 23026506, 23027186, 23029708, 23029708, 23037508, 23043110, 23044100, 23048122, 23051360, 23052698, 23056947, 23057753, 23059200, 23061160, 23062527, 23064972, 23065598, 23065598, 23069974, 23071944, 23074035, 23076476, 23077893, 23078492, 23078492, 23082644, 23087578, 23088109, 23088634, 23092404, 23095311, 23100980, 23102821, 23105624, 23108220, 23116990, 23117897, 23118372, 23120489, 23121131, 23122212, 23128049, 23128490, 23128776, 23129662, 23133942, 23142537, 23145682, 23148258, 23148258, 23149077, 23157421, 23157421, 23169412, 23170396, 23186180, 23187136, 23190917, 23264360, 23264360, 23279396, 23284922, 23285054, 23285191, 23285989, 23285989, 23286857, 23286857, 23287092, 23290002, 23290206, 23291387, 23301156, 23301803, 23303941, 23308488, 23308968, 23309238, 23309653, 23309737, 23310707, 23310707, 23311183, 23332062, 40004273, 40005002, 40005002, 40005810, 40005857, 40007407, 40007407, 40008578, 40014801, 40016240, 40020552, 40022736, 40030204, 40031019, 40039273, 40039273, 40040728, 40044069, 40048706, 40066523, 40074888, 40080274, 40082363, 40087353, 40088364, 40088512, 40090400, 40093243, 40096329, 40097147, 40099108, 40099108, 40100022, 40103831, 40104094, 40106381, 40108151, 40113338, 40114559, 40130436, 40136338, 40137723, 40140100, 40144256, 40144256, 40147753, 40171544, 40172243, 40173852, 40185846, 40188699, 40189205, 40191782, 40192433, 40192452, 40199959, 40201213, 40204737, 40214610, 40215672, 40217380, 40220230, 40231315, 40231776, 40239799, 40241602, 40243986, 40245042, 40246974, 40252925, 40254405, 40255803, 40257178, 40259147, 40259435, 40261585, 40264508, 40266935, 40270926, 40272078, 40275439, 40293157, 40293183, 40296160, 40303778, 40309917, 40316849, 40320986, 40331065, 40333188, 40339779, 40342537, 40345973, 40350250, 40351072, 40354938, 40361124, 40362732, 40366883, 40366883, 40373877, 40382136, 40382260, 40392599, 40392652, 40393970, 40394909, 40402465, 40404360, 40405082, 40405082, 40406885, 40406885, 40409422, 40414442, 40418294, 40418613, 40432427, 40437737, 40443608, 40443888, 40444105, 40446644, 40448699, 40450595, 40450871, 40452970, 40452970, 40455442, 40467832, 40473881, 40479115, 40479452, 40479596, 40480823, 40480823, 40487265, 40488102, 40488725, 40490272, 40493059, 40493088, 40496479, 40497851, 40501311, 40503324, 40506011, 40507460, 40511723, 40513494, 40513494, 40520883, 40525739, 40527738, 40530677, 40530816, 40531757, 40536959, 40536959, 40537603, 40537831, 40540709, 40544403, 40544737, 40547989, 40549529, 40550524, 40553143, 40557369, 40557524, 40558626, 40559053, 40561659, 40562821, 40563504, 40564382, 40564389, 40564512, 40564828, 40564849, 40564905, 40565143, 40565174, 40565291, 40565509, 40565520, 40565563, 40565772, 40566354, 40566596, 40566811, 40567495, 40567516, 40567778, 40567844, 40568010, 40568105, 40568543, 40569200, 40569232, 40569539, 40569914, 40570266, 40570276, 40570566, 40570878, 40570901, 40571240, 40571475, 40571488, 40572427, 40572538, 40572611, 40572694, 40572836, 40574472, 40576855, 40577502, 40577561, 40578508, 40578650, 40579199, 40579911, 40580124, 40580290, 40581210, 40581210, 40581302, 40581354, 40581423, 40581692, 40581807, 40582191, 40582397, 40586052, 40587327, 40587592, 40588362, 40589053, 40594541, 40594664, 40595586, 40598283, 40598746, 40598891, 40598926, 40599327, 40600255, 40600514, 40600610, 40604152, 40604326, 40605359, 40621653, 40624432, 40626413, 40626880, 40626970, 40627492], "handles": null, @@ -81,14 +77,12 @@ }, { "id": 15101, "name": "Time Series Learning", - "type": "mmatches", "status": "PAST", "startDate": "2016-07-01T19:36:00.000Z", "endDate": "2016-07-01T19:36:00.000Z", - "legacy": { - "track": "DATA_SCIENCE" - }, - "subTrack": "MARATHON_MATCH", + "track": "Data Science", + "type": "Challenge", + "tags": ["Marathon Match"], "numOfRegistrants": null, "userIds": [154140, 269874, 272273, 278182, 278995, 288224, 295533, 299658, 346860, 7213681, 7218883, 7442498, 7454975, 7456002, 7486189, 7524742, 8351376, 8368688, 8378182, 8447720, 8534923, 10223128, 10389461, 10407399, 10410959, 10597114, 10622349, 10622813, 10651584, 10697386, 11789293, 11943911, 11960667, 13298470, 13365783, 13386938, 14850928, 14883513, 15217330, 15580072, 15620282, 15700523, 15759076, 21050876, 21074047, 21245720, 21260340, 21348747, 21841130, 22653678, 22654637, 22657324, 22667224, 22668509, 22672939, 22673010, 22676578, 22678451, 22681556, 22685471, 22686050, 22686885, 22687885, 22691367, 22691875, 22704193, 22704223, 22709036, 22709401, 22710961, 22712353, 22714511, 22720311, 22724786, 22724890, 22729347, 22735770, 22740598, 22741497, 22741638, 22744390, 22746169, 22747887, 22748602, 22748809, 22753197, 22763515, 22771322, 22772927, 22773629, 22774059, 22774534, 22774543, 22774735, 22774947, 22776986, 22826877, 22827765, 22830782, 22830911, 22832535, 22835245, 22837526, 22845571, 22849993, 22851426, 22851534, 22851695, 22854301, 22856136, 22856405, 22857667, 22860727, 22866234, 22866292, 22875797, 22881290, 22885065, 22886024, 22887668, 22889926, 22891205, 22892489, 22893041, 22895494, 22902778, 22902990, 22903221, 22904497, 22904503, 22906600, 22908168, 22910325, 22912943, 22913151, 22914111, 22914334, 22919728, 22923197, 22924440, 22925924, 22927475, 22930463, 22936420, 22938207, 23002104, 23004444, 23005048, 23006918, 23007392, 23014542, 23017446, 23018445, 23019419, 23022099, 23022695, 23029708, 23032149, 23037218, 23038038, 23038899, 23039183, 23043893, 23046001, 23047213, 23048327, 23049553, 23060302, 23060949, 23061767, 23061953, 23070173, 23070641, 23070657, 23070734, 23072035, 23073943, 23075604, 23077395, 23079943, 23080596, 23083557, 23084510, 23087191, 23090167, 23093966, 23095394, 23097902, 23100339, 23100953, 23100980, 23101059, 23101081, 23101315, 23102361, 23102940, 23104345, 23105719, 23107697, 23108023, 23108439, 23108623, 23112493, 23116063, 23116075, 23117698, 23119181, 23119757, 23124403, 23125504, 23127980, 23128049, 23128986, 23132066, 23133685, 23134944, 23135019, 23135687, 23135828, 23138103, 23139753, 23140177, 23145576, 23148540, 23149729, 23151567, 23155371, 23155492, 23156903, 23156915, 23157098, 23160221, 23160794, 23184582, 23184834, 23195087, 23200855, 23202082, 23202937, 23274070, 23292810, 23293318, 23302899, 23307371, 23309814, 23309825, 23332647, 40001257, 40004159, 40005002, 40005810, 40007407, 40021371, 40033982, 40047615, 40048545, 40056331, 40057691, 40061486, 40062829, 40063560, 40064456, 40066329, 40067461, 40068262, 40068271, 40074153, 40074818, 40078304, 40078665, 40082879, 40087294, 40088364, 40088512, 40090400, 40090611, 40091871, 40094376, 40096710, 40098002, 40100067, 40100985, 40113361, 40114315, 40143464, 40144256, 40169606, 40171293, 40178963, 40179229, 40181241, 40181568, 40183109, 40188938, 40192587, 40192860, 40194929, 40199959, 40200221, 40202985, 40204368, 40205303, 40206067, 40207670, 40210548, 40210613, 40210665, 40213206, 40214489, 40215779, 40217185, 40219699, 40220714, 40220917, 40224034, 40224563, 40227481, 40233048, 40234303, 40234331, 40236485, 40237717, 40242737, 40243674, 40243869, 40244398, 40246318, 40247029, 40250420, 40250885, 40253929, 40254603, 40255353, 40256114, 40259287, 40259717, 40260287, 40263733, 40265124, 40267774, 40267805, 40272727, 40272788, 40275927, 40278661, 40278748, 40282544, 40283914, 40284020, 40285475, 40289457, 40295694, 40296802, 40305675, 40309798, 40312517, 40313123, 40314028, 40319457, 40321860, 40324216, 40325141, 40326063, 40327774, 40331705, 40332631, 40337197, 40338897, 40339564, 40341972, 40342537, 40342983, 40347683, 40351145, 40351980, 40352132, 40352345, 40352844, 40355569, 40356777, 40358242, 40358649, 40358790, 40361537, 40362263, 40362879, 40363213, 40363533, 40364699, 40369248, 40369400, 40369686, 40375460, 40377128, 40378058, 40380344, 40380865, 40380879, 40381328, 40381516, 40382590, 40386073, 40389458, 40390334, 40391430, 40391788, 40393144, 40394268, 40394701, 40395226, 40396292, 40396939, 40397138, 40419332, 40431793, 40445620, 40446698, 40448856, 40450235, 40453619, 40453872, 40454407, 40454568, 40456037, 40456117, 40456616, 40457254, 40457312, 40457501, 40457659, 40458164, 40458449, 40458819, 40459217, 40459388, 40459442, 40460262, 40460306, 40460587, 40461042, 40462020, 40462061, 40462750, 40464922, 40465528], "handles": null, @@ -121,14 +115,12 @@ }, { "id": 15082, "name": "Fishing for Fishermen", - "type": "mmatches", "status": "PAST", "startDate": "2016-05-06T13:11:00.000Z", "endDate": "2016-05-06T13:11:00.000Z", - "legacy": { - "track": "DATA_SCIENCE" - }, - "subTrack": "MARATHON_MATCH", + "track": "Data Science", + "type": "Challenge", + "tags": ["Marathon Match"], "numOfRegistrants": null, "userIds": [142908, 151743, 151743, 279175, 293608, 295809, 296689, 299068, 7213681, 7442498, 7481999, 7486189, 7488783, 8351376, 8415179, 8445979, 9916266, 10597114, 10664765, 11789293, 11793516, 11928645, 13274356, 13281173, 13365783, 14867032, 14883513, 15151937, 15180452, 15391415, 15580072, 15599488, 15722497, 15781032, 16017427, 16286638, 19938079, 20680885, 20765681, 21407357, 21411972, 21866691, 22412992, 22627064, 22627112, 22630158, 22630232, 22630497, 22635191, 22637267, 22640357, 22651906, 22652845, 22655287, 22658052, 22663924, 22667224, 22668870, 22671291, 22671608, 22680214, 22686050, 22686590, 22686885, 22688672, 22690116, 22690327, 22691355, 22698098, 22698830, 22700085, 22700843, 22704303, 22704672, 22704801, 22708072, 22711181, 22718910, 22723258, 22723321, 22735770, 22736823, 22739669, 22742639, 22745596, 22746398, 22746456, 22749362, 22750962, 22752626, 22753197, 22754202, 22759498, 22768416, 22769001, 22769513, 22772511, 22773629, 22774059, 22774534, 22775072, 22775328, 22776011, 22778882, 22779022, 22779022, 22788800, 22789553, 22792908, 22793803, 22794225, 22820771, 22821001, 22825438, 22827337, 22827765, 22828541, 22830782, 22831125, 22837733, 22839528, 22840269, 22842716, 22843062, 22845163, 22849993, 22850373, 22851067, 22854046, 22854046, 22854212, 22857866, 22862481, 22863278, 22869667, 22874592, 22875790, 22875864, 22880063, 22880988, 22881559, 22883575, 22885145, 22885430, 22886024, 22886772, 22886819, 22887668, 22887777, 22895494, 22897296, 22900997, 22902778, 22903595, 22908058, 22908168, 22908168, 22908615, 22910325, 22917960, 22918510, 22921130, 22921568, 22923054, 22923352, 22924902, 22927726, 22929867, 22934252, 22938617, 23007222, 23007392, 23014314, 23016457, 23017314, 23022695, 23023538, 23026150, 23028047, 23032874, 23036027, 23041060, 23044638, 23044783, 23046001, 23047804, 23052854, 23065483, 23065609, 23070656, 23072396, 23072596, 23073157, 23074259, 23076137, 23076347, 23077395, 23079284, 23080306, 23082619, 23086074, 23086763, 23092404, 23094828, 23098184, 23100414, 23100954, 23100980, 23101046, 23101424, 23102281, 23102542, 23102940, 23105260, 23106761, 23106916, 23108754, 23112987, 23114169, 23118563, 23120215, 23122214, 23122959, 23123632, 23123669, 23124115, 23125273, 23125504, 23126283, 23127404, 23127692, 23127980, 23127980, 23128049, 23128776, 23128883, 23129652, 23130114, 23132066, 23132066, 23133000, 23134944, 23139211, 23139220, 23140177, 23147327, 23150794, 23151567, 23152336, 23155371, 23159762, 23160532, 23162763, 23168056, 23176484, 23179943, 23184924, 23188776, 23192532, 23197396, 23198223, 23198757, 23202924, 23234803, 23278975, 23279396, 23283610, 23283906, 23288665, 23290206, 23297195, 23300447, 23300521, 23301671, 23304700, 23305574, 23306597, 23307774, 23309496, 23309546, 23320928, 23323428, 23330618, 40001257, 40005002, 40005810, 40007407, 40007407, 40009115, 40010714, 40020024, 40026260, 40029145, 40032295, 40032589, 40034358, 40037314, 40039485, 40040405, 40044770, 40056188, 40059065, 40061863, 40062829, 40063127, 40064981, 40065599, 40066065, 40066242, 40066625, 40067461, 40067461, 40069457, 40070692, 40072908, 40072930, 40073742, 40075054, 40075561, 40075671, 40080692, 40081537, 40081669, 40082394, 40084125, 40085239, 40086566, 40088180, 40088364, 40088512, 40088701, 40090611, 40091871, 40093687, 40096911, 40100111, 40102877, 40103984, 40107604, 40113361, 40124023, 40140100, 40141423, 40144256, 40144969, 40147646, 40149844, 40153583, 40167235, 40167842, 40183109, 40183109, 40186683, 40191031, 40191492, 40191778, 40191782, 40192860, 40193540, 40194435, 40194933, 40195993, 40196390, 40200221, 40202018, 40204737, 40207513, 40207670, 40212329, 40213206, 40214489, 40214903, 40218877, 40219415, 40220361, 40221271, 40222205, 40224106, 40224472, 40229150, 40231315, 40233706, 40234126, 40234399, 40234861, 40235957, 40237646, 40241602, 40244221, 40245250, 40246611, 40246639, 40247073, 40251078, 40254405, 40257255, 40258456, 40258608, 40259383, 40259530, 40259691, 40261342, 40262800, 40262973, 40263629, 40265406, 40265492, 40265905, 40267134, 40269829, 40274368, 40280039, 40282512, 40283567, 40285217, 40288654, 40292200, 40292943, 40293431, 40293928, 40296279, 40303778, 40303991, 40304139, 40304510, 40305468, 40306100, 40310003, 40313244, 40313677, 40314769, 40316574, 40316924, 40318475, 40320986, 40324321, 40324495, 40324629, 40325667, 40326039, 40326874, 40329558, 40329971, 40330223, 40331322, 40332666, 40334304, 40334968, 40338325, 40339970, 40340301, 40340435, 40340469, 40342754, 40347683, 40347857, 40352345, 40353605, 40355723, 40355761, 40356777, 40357095, 40357972, 40358124, 40359327, 40361361, 40361537, 40362767, 40363459, 40364310, 40364585, 40366499, 40367795, 40369248, 40369400, 40370272, 40372057, 40372223, 40372380, 40373244, 40373700, 40375460, 40378989, 40380802, 40380879, 40381462, 40382590, 40384005, 40384505, 40384803, 40385125, 40385394, 40385403, 40386451, 40387078, 40387351, 40388271, 40388603, 40390870, 40391430, 40391939, 40394555, 40396739, 40397420, 40397575, 40397639, 40397997, 40403127, 40414455, 40423451, 40426689, 40427723, 40431286, 40433248, 40436953, 40438898, 40441921, 40444049, 40444320, 40450235, 40450314, 40450918, 40452934, 40455903, 40457312, 40457633, 40460918, 40464919, 40469765, 40470531, 40473175, 40474803, 40476142, 40476158, 40476834, 40477287, 40477855, 40478009, 40478522, 40478650, 40478901, 40478913, 40479144, 40479330, 40479909, 40480417, 40480837, 40480933, 40481451, 40481769, 40482187, 40482585, 40482994, 40483072, 40483713, 40483756, 40483895, 40483949, 40484117, 40493705, 40504027, 40508627, 40513900, 40546706, 40572860, 40578481, 40582837, 40598280, 40599650, 40602371, 40606816, 40608419, 40618557, 40620604, 40623546, 40623721, 40623736, 40623755, 40623780, 40623843, 40623863, 40623880, 40624049, 40624183, 40624262, 40624322, 40624431, 40624470, 40625076, 40625201, 40625266, 40625395, 40625427, 40625451, 40625622, 40625810, 40626032, 40626643, 40627777, 40628756, 40630725], "handles": null, diff --git a/__tests__/shared/components/ChallengeTile/__snapshots__/index.jsx.snap b/__tests__/shared/components/ChallengeTile/__snapshots__/index.jsx.snap index 801651ee39..26ba777088 100644 --- a/__tests__/shared/components/ChallengeTile/__snapshots__/index.jsx.snap +++ b/__tests__/shared/components/ChallengeTile/__snapshots__/index.jsx.snap @@ -12,7 +12,7 @@ exports[`renders design 1`] = ` } >
- LOGO DESIGN + Challenge

- FIRST 2 FINISH + First2Finish

- MARATHON MATCH + Challenge

+
`; diff --git a/__tests__/shared/components/Leaderboard/__snapshots__/LeaderboardTable.jsx.snap b/__tests__/shared/components/Leaderboard/__snapshots__/LeaderboardTable.jsx.snap index 8427f7e0c1..5ebefb6402 100644 --- a/__tests__/shared/components/Leaderboard/__snapshots__/LeaderboardTable.jsx.snap +++ b/__tests__/shared/components/Leaderboard/__snapshots__/LeaderboardTable.jsx.snap @@ -44,16 +44,10 @@ exports[`Matches shallow shapshot 1`] = ` - @@ -97,16 +91,10 @@ exports[`Matches shallow shapshot 1`] = ` - @@ -150,16 +138,10 @@ exports[`Matches shallow shapshot 1`] = ` - @@ -203,16 +185,10 @@ exports[`Matches shallow shapshot 1`] = ` - diff --git a/__tests__/shared/components/Leaderboard/__snapshots__/PodiumSpot.jsx.snap b/__tests__/shared/components/Leaderboard/__snapshots__/PodiumSpot.jsx.snap index 9a000a3094..7d868e9f5a 100644 --- a/__tests__/shared/components/Leaderboard/__snapshots__/PodiumSpot.jsx.snap +++ b/__tests__/shared/components/Leaderboard/__snapshots__/PodiumSpot.jsx.snap @@ -7,16 +7,10 @@ exports[`Matches shallow shapshot 1`] = ` -
-
Policies diff --git a/__tests__/shared/containers/__snapshots__/TopcoderHeader.jsx.snap b/__tests__/shared/containers/__snapshots__/TopcoderHeader.jsx.snap index 54b150a474..a68a045aea 100644 --- a/__tests__/shared/containers/__snapshots__/TopcoderHeader.jsx.snap +++ b/__tests__/shared/containers/__snapshots__/TopcoderHeader.jsx.snap @@ -11,6 +11,7 @@ exports[`Matches shallow snapshot 1`] = ` closeMobileMenu={[Function]} closeSearch={[Function]} dismissChallengeNotifications={[Function]} + headerMenu={null} loadNotifications={[Function]} markAllNotificationAsRead={[Function]} markAllNotificationAsSeen={[Function]} diff --git a/config/default.js b/config/default.js index e924db4123..483681f0dd 100644 --- a/config/default.js +++ b/config/default.js @@ -160,7 +160,6 @@ module.exports = { COMMUNITY_API: 'http://localhost:8000', COMMUNITY_APP_GITHUB_ISSUES: 'https://github.com/topcoder-platform/community-app/issues', EMAIL_VERIFY_URL: 'http://www.topcoder-dev.com/settings/account/changeEmail', - THRIVE_POLL_FEED: 'https://www.topcoder.com/feed', }, /* Information about Topcoder user groups can be cached in various places. @@ -406,9 +405,5 @@ module.exports = { TC_EDU_ARTICLES_PATH: '/articles', TC_EDU_SEARCH_PATH: '/search', TC_EDU_SEARCH_BAR_MAX_RESULTS_EACH_GROUP: 3, - - ENV: { - HOST: process.env.HOST, - PORT: process.env.PORT, - }, + POLICY_PAGES_PATH: '/policy', }; diff --git a/package-lock.json b/package-lock.json index 6387811315..7d082a3e47 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6135,6 +6135,11 @@ } } }, + "css-mediaquery": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/css-mediaquery/-/css-mediaquery-0.1.2.tgz", + "integrity": "sha1-aiw3NEkoYYYxxUvTPO3TAdoYvqA=" + }, "css-modules-loader-core": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/css-modules-loader-core/-/css-modules-loader-core-1.1.0.tgz", @@ -10678,6 +10683,11 @@ } } }, + "hyphenate-style-name": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/hyphenate-style-name/-/hyphenate-style-name-1.0.4.tgz", + "integrity": "sha512-ygGZLjmXfPHj+ZWh6LwbC37l43MhfztxetbFCoYTM2VjkIUpeHgSNn7QIyVFj7YQ1Wl9Cbw5sholVJPzWvC2MQ==" + }, "i18n-iso-countries": { "version": "3.7.8", "resolved": "https://registry.npmjs.org/i18n-iso-countries/-/i18n-iso-countries-3.7.8.tgz", @@ -13878,6 +13888,14 @@ "integrity": "sha512-ea2eGWOqNxPcXv8dyERdSr/6FmzvWwzjMxpfGB/sbMccXoct+xY+YukPD+QTUZwyvK7BZwcr4m21WBOW41pAkg==", "dev": true }, + "matchmediaquery": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/matchmediaquery/-/matchmediaquery-0.3.1.tgz", + "integrity": "sha512-Hlk20WQHRIm9EE9luN1kjRjYXAQToHOIAHPJn9buxBwuhfTHoKUcX+lXBbxc85DVQfXYbEQ4HcwQdd128E3qHQ==", + "requires": { + "css-mediaquery": "^0.1.2" + } + }, "material-colors": { "version": "1.2.6", "resolved": "https://registry.npmjs.org/material-colors/-/material-colors-1.2.6.tgz", @@ -14555,7 +14573,7 @@ "dev": true }, "navigation-component": { - "version": "github:topcoder-platform/navigation-component#3ff9165a545ba6210ea4cd992d0dd26b52610055", + "version": "github:topcoder-platform/navigation-component#4938269d5610f3f8bff65f23459a37d01121e6f6", "from": "github:topcoder-platform/navigation-component#develop", "requires": { "classnames": "^2.2.6", @@ -18381,6 +18399,17 @@ "resize-observer-polyfill": "^1.5.1" } }, + "react-responsive": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/react-responsive/-/react-responsive-8.1.0.tgz", + "integrity": "sha512-U8Nv2/ZWACIw/fAE9XNPbc2Xo33X5q1bcCASc2SufvJ9ifB+o/rokfogfznSVcvS22hN1rafGi0uZD6GiVFEHw==", + "requires": { + "hyphenate-style-name": "^1.0.0", + "matchmediaquery": "^0.3.0", + "prop-types": "^15.6.1", + "shallow-equal": "^1.1.0" + } + }, "react-router": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/react-router/-/react-router-4.3.1.tgz", @@ -20493,6 +20522,11 @@ "kind-of": "^6.0.2" } }, + "shallow-equal": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/shallow-equal/-/shallow-equal-1.2.1.tgz", + "integrity": "sha512-S4vJDjHHMBaiZuT9NPb616CSmLf618jawtv3sufLl6ivK8WocjAo58cXwbRV1cgqxH0Qbv+iUt6m05eqEa2IRA==" + }, "shallowequal": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz", @@ -22335,7 +22369,7 @@ } }, "tc-accounts": { - "version": "git+https://github.com/appirio-tech/accounts-app.git#9d0daa189dbf5127ad6ca470ed1683eeb2495ac7", + "version": "git+https://github.com/appirio-tech/accounts-app.git#33f4aeb29d07dbe4e6d8206d718830fd54943f47", "from": "git+https://github.com/appirio-tech/accounts-app.git#dev", "requires": { "@uirouter/angularjs": "^1.0.0", @@ -33162,9 +33196,9 @@ "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" }, "topcoder-react-lib": { - "version": "1000.19.44", - "resolved": "https://registry.npmjs.org/topcoder-react-lib/-/topcoder-react-lib-1000.19.44.tgz", - "integrity": "sha512-WoBJbt5w50Hdho9xCzUFwCL/JOQLE0mfMCY3Y0YMUNAToieDpE2RloOwHZpqez+QgE1sxehLGQxlf61M9NZ95A==", + "version": "1000.19.48", + "resolved": "https://registry.npmjs.org/topcoder-react-lib/-/topcoder-react-lib-1000.19.48.tgz", + "integrity": "sha512-TguboxXulPHmE8FGGBgxYlYNjEU7mDZwOT74SYzeAJLl4bZr6z7yQCwGIlksB9dzq6beAvDIm4sYXqTCRuUInw==", "requires": { "auth0-js": "^6.8.4", "config": "^3.2.0", diff --git a/package.json b/package.json index 71c961ba94..9ef32087c4 100644 --- a/package.json +++ b/package.json @@ -110,6 +110,7 @@ "react-player": "^0.24.1", "react-redux": "^5.0.7", "react-redux-toastr": "^7.2.6", + "react-responsive": "^8.1.0", "react-router": "^4.3.1", "react-router-dom": "^4.3.1", "react-select": "^1.2.0", @@ -135,7 +136,7 @@ "tc-accounts": "git+https://github.com/appirio-tech/accounts-app.git#dev", "tc-core-library-js": "github:appirio-tech/tc-core-library-js#v2.6.3", "tc-ui": "^1.0.12", - "topcoder-react-lib": "1000.19.44", + "topcoder-react-lib": "1000.19.48", "topcoder-react-ui-kit": "1000.0.4", "topcoder-react-utils": "0.7.8", "turndown": "^4.0.2", diff --git a/src/assets/images/default-avatar-photo.svg b/src/assets/images/default-avatar-photo.svg new file mode 100644 index 0000000000..b208ce37b4 --- /dev/null +++ b/src/assets/images/default-avatar-photo.svg @@ -0,0 +1 @@ +Avatar Photo \ No newline at end of file diff --git a/src/assets/images/icon-facebook.svg b/src/assets/images/icon-facebook.svg new file mode 100644 index 0000000000..ec2593813f --- /dev/null +++ b/src/assets/images/icon-facebook.svg @@ -0,0 +1,11 @@ + + + + 1EF461D5-8CE7-4936-91E5-80EBD141882D + Created with sketchtool. + + + + + + \ No newline at end of file diff --git a/src/assets/images/icon-linkedIn.svg b/src/assets/images/icon-linkedIn.svg new file mode 100644 index 0000000000..d7fbf67eaa --- /dev/null +++ b/src/assets/images/icon-linkedIn.svg @@ -0,0 +1,11 @@ + + + + A17EE70C-4FF2-418A-A9EE-80C7482C7231 + Created with sketchtool. + + + + + + \ No newline at end of file diff --git a/src/assets/images/icon-twitter.svg b/src/assets/images/icon-twitter.svg new file mode 100644 index 0000000000..d11f28d598 --- /dev/null +++ b/src/assets/images/icon-twitter.svg @@ -0,0 +1,11 @@ + + + + 98B36CB6-9363-4AE1-9293-675C31608E4A + Created with sketchtool. + + + + + + \ No newline at end of file diff --git a/src/assets/images/minimal-down.svg b/src/assets/images/minimal-down.svg new file mode 100644 index 0000000000..8a053c8f1e --- /dev/null +++ b/src/assets/images/minimal-down.svg @@ -0,0 +1,23 @@ + + + + C1A13778-3A8D-495F-8743-807086A83EFB + Created with sketchtool. + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/shared/actions/contentful.js b/src/shared/actions/contentful.js index 9db4a823b6..0ae1983713 100644 --- a/src/shared/actions/contentful.js +++ b/src/shared/actions/contentful.js @@ -297,6 +297,32 @@ async function getChallengesBlockDone(blockProps) { }; } +/** + * Policy pages fetch init + */ +function getPolicyPagesInit() { + return {}; +} + +/** + * Policy pages fetch done + */ +async function getPolicyPagesDone() { + const service = getService({ + preview: false, + spaceName: 'default', + environment: 'master', + }); + + const res = await service.queryEntries({ + content_type: 'policyPage', + }); + + return { + data: [...res.items], + }; +} + export default redux.createActions({ CONTENTFUL: { BOOK_CONTENT: bookContent, @@ -312,5 +338,7 @@ export default redux.createActions({ GET_MENU_DONE: getMenuDone, GET_CHALLENGES_BLOCK_INIT: getChallengesBlockInit, GET_CHALLENGES_BLOCK_DONE: getChallengesBlockDone, + GET_POLICY_PAGES_INIT: getPolicyPagesInit, + GET_POLICY_PAGES_DONE: getPolicyPagesDone, }, }); diff --git a/src/shared/actions/leaderboard.js b/src/shared/actions/leaderboard.js index 5fbc73a665..e1216d3301 100644 --- a/src/shared/actions/leaderboard.js +++ b/src/shared/actions/leaderboard.js @@ -42,7 +42,11 @@ async function getTcoHistoryChallengesDone(url, competitor) { const res = await fetch(url) .then(response => response.json()) .then(jsonResponse => ({ - challenges: _.filter(jsonResponse, challenge => challenge.userid === competitor.userid), + challenges: _.filter(jsonResponse, challenge => ( + challenge['tco_leaderboard.user_id'] + ? (challenge['tco_leaderboard.user_id'] === competitor['tco_leaderboard.user_id']) + : (challenge.userid === competitor.userid) + )), })); return res; } diff --git a/src/shared/components/ChallengeTile/index.jsx b/src/shared/components/ChallengeTile/index.jsx index 740439ca90..47e389c869 100644 --- a/src/shared/components/ChallengeTile/index.jsx +++ b/src/shared/components/ChallengeTile/index.jsx @@ -6,7 +6,8 @@ import _ from 'lodash'; import React from 'react'; import PT from 'prop-types'; import { Link } from 'react-router-dom'; -import { formatDate } from 'utils/tc'; +import { formatDate, COMPETITION_TRACKS } from 'utils/tc'; +import { isMM } from 'utils/challenge'; import ReactImageFallback from 'react-image-fallback'; import InviteOnly from 'assets/images/ico-invite-only-prj.svg'; import WinnerRibbon from 'assets/images/ico-winner-ribbon.svg'; @@ -73,23 +74,27 @@ class ChallengeTile extends React.Component { challenge, } = this.props; - const { track } = challenge.legacy; + const { track, type } = challenge; - const outStyleName = `challenge tile-view ${track}`; + const outStyleName = `challenge tile-view ${track.replace(' ', '-').toLowerCase()}`; const extraStyle = { width: '285px', padding: '15px', margin: '10px 5px', }; - const roundId = track === 'DATA_SCIENCE' ? _.get(challenge, 'rounds.0.id') : 0; + const isDataScience = track === COMPETITION_TRACKS.DATA_SCIENCE; + const isDevelopment = track === COMPETITION_TRACKS.DEVELOP; + const isDesign = track === COMPETITION_TRACKS.DESIGN; + + const roundId = isDataScience ? _.get(challenge, 'rounds.0.id') : 0; return (
- { track !== 'DATA_SCIENCE' && (!challenge.isPrivate + { !isDataScience && (!challenge.isPrivate ? ( @@ -102,7 +107,7 @@ class ChallengeTile extends React.Component { )) } - { track === 'DATA_SCIENCE' + { isDataScience && ( { challenge.name } @@ -110,7 +115,7 @@ class ChallengeTile extends React.Component { ) }

- {underscoreReplace(challenge.subTrack)} + {underscoreReplace(type)}

{formatDate(challenge.submissionEndDate)} @@ -124,8 +129,8 @@ class ChallengeTile extends React.Component { }

-
- { track === 'DATA_SCIENCE' && challenge.subTrack +
+ { isMM(challenge) && (

@@ -136,7 +141,7 @@ class ChallengeTile extends React.Component {

) } - { track === 'DEVELOP' + { isDevelopment && (
@@ -193,7 +198,7 @@ class ChallengeTile extends React.Component { ) } { - track === 'DESIGN' && !challenge.isPrivate + isDesign && !challenge.isPrivate && (
@@ -313,7 +318,7 @@ class ChallengeTile extends React.Component {

- { track !== 'DATA_SCIENCE' + { track !== COMPETITION_TRACKS.DATA_SCIENCE && ( diff --git a/src/shared/components/ChallengeTile/style.scss b/src/shared/components/ChallengeTile/style.scss index 3af069c42c..db72e7a56e 100644 --- a/src/shared/components/ChallengeTile/style.scss +++ b/src/shared/components/ChallengeTile/style.scss @@ -77,7 +77,7 @@ } // Dynamic colors based on track -.DESIGN { +.design { &.tile-view { header { border-left: 3px solid #21b2f1; @@ -94,7 +94,7 @@ } } -.DEVELOP { +.development { &.tile-view { header { border-left: 3px solid #05c14f; @@ -111,7 +111,7 @@ } } -.DATA_SCIENCE { +.data-science { &.tile-view { header { border-left: 3px solid #fc9a00; diff --git a/src/shared/components/Contentful/Article/Article.jsx b/src/shared/components/Contentful/Article/Article.jsx index 809f7c909c..150d213290 100644 --- a/src/shared/components/Contentful/Article/Article.jsx +++ b/src/shared/components/Contentful/Article/Article.jsx @@ -15,13 +15,14 @@ import LoadingIndicator from 'components/LoadingIndicator'; import YouTubeVideo from 'components/YouTubeVideo'; import moment from 'moment'; import localStorage from 'localStorage'; -import { config } from 'topcoder-react-utils'; -import ShareSocial from 'components/challenge-detail/Specification/SideBar/ShareSocial'; +import { config, Link, isomorphy } from 'topcoder-react-utils'; +import qs from 'qs'; // SVGs and assets import GestureIcon from 'assets/images/icon-gesture.svg'; -import UserDefault from 'assets/images/ico-user-default.svg'; import ReadMoreArrow from 'assets/images/read-more-arrow.svg'; -import qs from 'qs'; +import IconFacebook from 'assets/images/icon-facebook.svg'; +import IconTwitter from 'assets/images/icon-twitter.svg'; +import IconLinkedIn from 'assets/images/icon-linkedIn.svg'; const htmlToText = require('html-to-text'); @@ -105,20 +106,31 @@ export default class Article extends React.Component { spaceName, environment, preview, }; const { upvotes, downvotes } = this.state || {}; + let shareUrl; + if (isomorphy.isClientSide()) { + shareUrl = encodeURIComponent(window.location.href); + } return ( {/* Banner */} -

- { - fields.featuredImage ? ( -
- ) : null - } -
-
+ { + fields.featuredImage ? ( +
+ + + + + + + + +
+ ) : null + }
@@ -139,9 +151,7 @@ export default class Article extends React.Component { )} renderPlaceholder={LoadingIndicator} /> - ) : ( - - ) + ) : null }
@@ -169,14 +179,24 @@ export default class Article extends React.Component { { _.map(fields.tags, tag => (
- {tag} + {tag}
)) }

share

- +
{/* Content */} @@ -250,9 +270,9 @@ export default class Article extends React.Component { {subData.entries.items[rec.sys.id].fields.title} ) : ( - + {subData.entries.items[rec.sys.id].fields.title} - + ) } @@ -278,9 +298,9 @@ export default class Article extends React.Component { Read More ) : ( - + Read More - + ) }
diff --git a/src/shared/components/Contentful/Article/themes/default.scss b/src/shared/components/Contentful/Article/themes/default.scss index b823211fca..5b9b4b32a6 100644 --- a/src/shared/components/Contentful/Article/themes/default.scss +++ b/src/shared/components/Contentful/Article/themes/default.scss @@ -1,23 +1,22 @@ @import "~styles/mixins"; @import "~components/Contentful/default"; -.bannerBottomShape { - background-image: url(assets/images/wave.svg); - height: 120px; - background-repeat: no-repeat; - background-size: cover; - margin-top: -120px; - position: relative; +.shareButtons { + margin-top: 10px; - @include xs-to-sm { - height: 60px; - margin-top: -60px; + a { + margin-right: 5px; + + &:last-child { + margin-right: 0; + } } } -.contentContainer { +.contentContainer, +.contentContainerWithBanner { max-width: $screen-lg; - margin: 90px auto; + margin: 70px auto 90px auto; width: 100%; display: flex; @@ -67,13 +66,18 @@ } .name { - @include roboto-regular; + @include roboto-bold; margin-right: 6px; + color: #2a2a2a; + font-size: 14px; } .handle { - @include roboto-bold; + @include roboto-regular; + + color: #2a2a2a; + font-size: 14px; } } } @@ -411,17 +415,21 @@ } } +.contentContainerWithBanner { + margin-top: 0; +} + .bannerContainer { - background-image: linear-gradient(0deg, #06d6a0 0%, #63f963 100%); - position: relative; - min-height: 600px; + margin: auto; + max-width: 1024px; + width: 100%; - .featuredImage { - background-repeat: no-repeat; - background-size: cover; - background-position: center center; + @include xs-to-md { + padding: 0 15px; + } + + .site-header-background { width: 100%; - min-height: 600px; } } diff --git a/src/shared/components/Contentful/ArticleCard/ArticleCard.jsx b/src/shared/components/Contentful/ArticleCard/ArticleCard.jsx index d50230a139..38e99630a3 100644 --- a/src/shared/components/Contentful/ArticleCard/ArticleCard.jsx +++ b/src/shared/components/Contentful/ArticleCard/ArticleCard.jsx @@ -10,7 +10,7 @@ import { logger } from 'topcoder-react-lib'; import PT from 'prop-types'; import React from 'react'; import { themr } from 'react-css-super-themr'; -import { config } from 'topcoder-react-utils'; +import { config, Link } from 'topcoder-react-utils'; import markdown from 'utils/markdown'; import ReactDOMServer from 'react-dom/server'; // SVG assets @@ -29,7 +29,7 @@ const FORMAT = 'MMM DD, YYYY'; // date/time format for 'Forum post' cards is different from others const FORUM_POST_FORMAT = 'MMM DD, YYYY [at] h:mm A'; // max length for the title of the 'Article small' cards -const ART_SMALL_TITLE_MAX_LENGTH = 29; +const ART_SMALL_TITLE_MAX_LENGTH = 60; // Article large card 'breakpoint' const ARTICLE_LARGE_BREAKPOINT = 473; // character length for the content preview @@ -185,7 +185,7 @@ class ArticleCard extends React.Component { className={theme.tag} title={`Search for articles labelled as ${tag}`} > - {tag} + {tag} )) /* eslint-enable react/no-array-index-key */ @@ -195,13 +195,13 @@ class ArticleCard extends React.Component {

{article.readTime}

- {title} - +

{content}

@@ -226,14 +226,14 @@ class ArticleCard extends React.Component {
) } - {author.tcHandle} - +
)) ) : null @@ -253,13 +253,13 @@ class ArticleCard extends React.Component { {themeName === 'Article large' ?  .  : null} { contentAuthor && contentAuthor.length > 0 ? ( - {contentAuthor[0].name} - + ) : null }

@@ -290,13 +290,13 @@ class ArticleCard extends React.Component { }
) : ( - Read More - + ) }
diff --git a/src/shared/components/Contentful/ArticleCard/themes/article_small.scss b/src/shared/components/Contentful/ArticleCard/themes/article_small.scss index 7037ddff2d..b750b8ad1d 100644 --- a/src/shared/components/Contentful/ArticleCard/themes/article_small.scss +++ b/src/shared/components/Contentful/ArticleCard/themes/article_small.scss @@ -26,6 +26,9 @@ .main { flex-grow: 1; padding: 0 20px; + display: flex; + flex-direction: column; + justify-content: space-around; } .playIconContainer { @@ -68,15 +71,9 @@ color: #2a2a2a; font-family: 'Barlow', Helvetica, Arial, sans-serif; font-weight: 600; - font-size: 20px; - line-height: 22px; + font-size: 16px; + line-height: 20px; text-transform: uppercase; - letter-spacing: 0.3px; - - @include xs-to-sm { - font-size: 21px; - line-height: 23px; - } } .contentPreview { @@ -85,6 +82,9 @@ .infoContainer { margin: 11px 0 15px; + flex: 1; + display: flex; + align-items: flex-end; } .articleInfo { diff --git a/src/shared/components/Contentful/ContentBlock/themes/TCO19.scss b/src/shared/components/Contentful/ContentBlock/themes/TCO19.scss index 6dd6d736f7..737dff7cca 100644 --- a/src/shared/components/Contentful/ContentBlock/themes/TCO19.scss +++ b/src/shared/components/Contentful/ContentBlock/themes/TCO19.scss @@ -52,141 +52,7 @@ strong a { } @include gui-kit-headers; - - p { - @include tc-body-md; - - color: $tco-black; - font-size: 16px; - line-height: 26px; - margin-bottom: 20px; - margin-top: 0; - - strong { - @include roboto-medium; - - line-height: 20px; - text-align: left; - font-weight: 600; - margin-bottom: 20px; - } - } - - table { - margin-bottom: 20px; - - th { - @include roboto-regular; - - color: #2a2a2a; - font-size: 15px; - font-weight: bold; - line-height: 18px; - text-align: left; - text-transform: uppercase; - padding: 18px 10px 14px 0; - - @include md-to-xl { - white-space: nowrap; - } - - &:first-child { - padding-left: 10px; - } - } - - td { - @include roboto-regular; - - font-size: 15px; - line-height: 25px; - text-align: left; - color: $tc-gray-80; - border-top: 1px solid #d4d4d4; - border-bottom: 1px solid #d4d4d4; - padding: 20px 50px 20px 0; - min-height: 51px; - - &:first-child { - padding-left: 10px; - } - - &:last-child { - padding-right: 10px; - } - } - } - - ul, - ol { - @include tc-body-md; - - padding-left: 20px; - margin-bottom: 20px; - - @include roboto-regular; - - color: $tc-black; - - li p { - margin-bottom: 0; - } - } - - ul { - list-style-type: disc; - } - - ol { - list-style-type: decimal; - } - - img { - max-width: 100%; - border-radius: 6px; - } - - code { - @include roboto-mono-regular; - - color: #2a2a2a; - line-height: 1.5; - white-space: pre; - } - - sub, - sup { - font-size: 75%; - line-height: 0; - position: relative; - vertical-align: baseline; - } - - sup { - top: -0.5em; - } - - sub { - bottom: -0.25em; - } - - a { - @include roboto-regular; - - font-size: 16px; - line-height: 24px; - color: #0d61bf; - text-decoration: underline; - - &:hover { - text-decoration: none; - color: #0d61bf; - } - - &:visited { - color: #8231a9; - } - } + @include gui-kit-content; } .image { diff --git a/src/shared/components/Contentful/ContentBlock/themes/TCO20.scss b/src/shared/components/Contentful/ContentBlock/themes/TCO20.scss index e6b4a5a3e7..c54525c0c5 100644 --- a/src/shared/components/Contentful/ContentBlock/themes/TCO20.scss +++ b/src/shared/components/Contentful/ContentBlock/themes/TCO20.scss @@ -51,140 +51,7 @@ strong a { } @include gui-kit-headers; - - a { - @include roboto-regular; - - font-size: 16px; - line-height: 24px; - color: #0d61bf; - text-decoration: underline; - - &:hover { - text-decoration: none; - color: #0d61bf; - } - - &:visited { - color: #8231a9; - } - } - - p { - @include tc-body-md; - - color: $tco-black; - font-size: 16px; - line-height: 26px; - margin-bottom: 20px; - margin-top: 0; - - strong { - @include roboto-medium; - - line-height: 20px; - text-align: left; - font-weight: 600; - } - } - - table { - margin-bottom: 20px; - - th { - @include roboto-regular; - - color: #2a2a2a; - font-size: 15px; - font-weight: bold; - line-height: 18px; - text-align: left; - text-transform: uppercase; - padding: 18px 10px 14px 0; - - @include md-to-xl { - white-space: nowrap; - } - - &:first-child { - padding-left: 10px; - } - } - - td { - @include roboto-regular; - - font-size: 15px; - line-height: 25px; - text-align: left; - color: $tc-gray-80; - border-top: 1px solid #d4d4d4; - border-bottom: 1px solid #d4d4d4; - padding: 20px 50px 20px 0; - min-height: 51px; - - &:first-child { - padding-left: 10px; - } - - &:last-child { - padding-right: 10px; - } - } - } - - ul, - ol { - @include tc-body-md; - - padding-left: 20px; - margin-bottom: 20px; - - @include roboto-regular; - - color: $tc-black; - - li p { - margin-bottom: 0; - } - } - - ul { - list-style-type: disc; - } - - ol { - list-style-type: decimal; - } - - img { - max-width: 100%; - border-radius: 6px; - } - - code { - @include roboto-mono-regular; - - color: #2a2a2a; - line-height: 1.5; - white-space: pre; - } - - sub, - sup { - font-size: 75%; - line-height: 0; - position: relative; - vertical-align: baseline; - } - - sup { - top: -0.5em; - } - - sub { - bottom: -0.25em; - } + @include gui-kit-content; } .image { diff --git a/src/shared/components/Contentful/Dropdown/DropdownItem.jsx b/src/shared/components/Contentful/Dropdown/DropdownItem.jsx new file mode 100644 index 0000000000..1c7d36cee9 --- /dev/null +++ b/src/shared/components/Contentful/Dropdown/DropdownItem.jsx @@ -0,0 +1,68 @@ +/** + * Question and Answer Component + */ +/* eslint-disable react/no-danger */ +import React from 'react'; +import PT from 'prop-types'; +import MarkdownRenderer from 'components/MarkdownRenderer'; + +import './item.scss'; + +class DropdownItem extends React.Component { + constructor(props) { + super(props); + this.state = { + isActive: props.isActive, + }; + } + + toggleActive() { + const { isActive } = this.state; + this.setState({ + isActive: !isActive, + }); + } + + render() { + const { data } = this.props; + const { isActive } = this.state; + return ( +
+
(e.key === 'Enter' ? null : null)} + styleName={isActive ? 'question active' : 'question'} + onClick={() => this.toggleActive()} + > +
+ {data.fields.title} +
+
+
+
+ +
+
+ ); + } +} + +DropdownItem.defaultProps = { + preview: false, + spaceName: null, + environment: null, + isActive: false, +}; + +DropdownItem.propTypes = { + data: PT.shape().isRequired, + isActive: PT.bool, + preview: PT.bool, + spaceName: PT.string, + environment: PT.string, +}; + +export default DropdownItem; diff --git a/src/shared/components/Contentful/Dropdown/default.scss b/src/shared/components/Contentful/Dropdown/default.scss index 3be8c346bb..9022565a91 100644 --- a/src/shared/components/Contentful/Dropdown/default.scss +++ b/src/shared/components/Contentful/Dropdown/default.scss @@ -1,27 +1,18 @@ @import "~styles/mixins"; -.contentWrapper { - display: flex; - margin: 0 auto; - max-width: $screen-md; - padding: 15px; - color: black; +.container { + padding: 0; @include xs-to-sm { - flex-direction: column; + padding: 0 15px; } } -.container { - align-content: center; - background: white; - padding: 10px 0; - - &:nth-child(even) .contentWrapper { - flex-direction: row-reverse; - - @include xs-to-sm { - flex-direction: column; - } - } +.contentWrapper { + display: flex; + margin: 0 auto; + max-width: $screen-md; + color: black; + flex-direction: column; + border-top: 1px solid #d4d4d4; } diff --git a/src/shared/components/Contentful/Dropdown/index.jsx b/src/shared/components/Contentful/Dropdown/index.jsx index 95d9ea6c5a..92d6505fec 100644 --- a/src/shared/components/Contentful/Dropdown/index.jsx +++ b/src/shared/components/Contentful/Dropdown/index.jsx @@ -7,8 +7,8 @@ import ContentfulLoader from 'containers/ContentfulLoader'; import LoadingIndicator from 'components/LoadingIndicator'; import PT from 'prop-types'; import React from 'react'; -import FAQ from 'components/TrackHomePages/HowToCompetePage/FAQ'; import { fixStyle } from 'utils/contentful'; +import DropdownItem from './DropdownItem'; import defaultTheme from './default.scss'; @@ -27,7 +27,15 @@ function DropdownItemsLoader(props) { spaceName={spaceName} environment={environment} render={data => ( - item) }} hashLink="" /> + _.map(data.entries.items, item => ( + + )) )} renderPlaceholder={LoadingIndicator} /> diff --git a/src/shared/components/Contentful/Dropdown/item.scss b/src/shared/components/Contentful/Dropdown/item.scss new file mode 100644 index 0000000000..7cd898b901 --- /dev/null +++ b/src/shared/components/Contentful/Dropdown/item.scss @@ -0,0 +1,59 @@ +@import "~styles/mixins"; +@import "~components/Contentful/default"; + +.container { + width: 100%; +} + +.question { + display: flex; + align-items: center; + justify-content: space-between; + height: 82px; + outline: none; + cursor: pointer; + border-bottom: 1px solid #d4d4d4; + + &.active { + border-bottom: none; + } +} + +.answer { + @include gui-kit-content; + @include gui-kit-headers; + + display: none; + padding: 5px 70px 24px 0; + color: #2a2a2a; + + &.active { + display: block; + border-bottom: 1px solid #d4d4d4; + } +} + +.text { + color: #2a2a2a; + font-family: BarlowCondensed, sans-serif; + font-size: 31px; + letter-spacing: 0.2px; + text-transform: uppercase; + font-weight: 500; + + @include xs-to-sm { + max-width: 350px; + } +} + +.toggle-arrow { + background-image: url(assets/images/minimal-down.svg); + background-repeat: no-repeat; + align-self: right; + width: 24px; + height: 13px; + + &.active { + transform: scale(1, -1); + } +} diff --git a/src/shared/components/Contentful/Image/index.jsx b/src/shared/components/Contentful/Image/index.jsx index 333bf02fef..e24a1eb694 100644 --- a/src/shared/components/Contentful/Image/index.jsx +++ b/src/shared/components/Contentful/Image/index.jsx @@ -7,6 +7,7 @@ import LoadingIndicator from 'components/LoadingIndicator'; import PT from 'prop-types'; import React from 'react'; import _ from 'lodash'; +import { useMediaQuery } from 'react-responsive'; import Image from './Image'; import defaultTheme from './themes/default.scss'; @@ -17,6 +18,7 @@ export default function ImageLoader(props) { const { id, preview, spaceName, environment, } = props; + const isTabletOrMobile = useMediaQuery({ maxWidth: 768 }); return ( { const { fields } = data.entries.items[id]; - const imgId = _.get(fields, 'source.sys.id'); + const imgId = _.get(fields, isTabletOrMobile && fields.sourceMobile ? 'sourceMobile.sys.id' : 'source.sys.id'); const clipSvgId = _.get(fields, 'clipSvg.sys.id'); const assetIds = _.compact([imgId, clipSvgId]); const animationId = _.get(fields, 'animationOnScroll.sys.id'); diff --git a/src/shared/components/Contentful/Tabs/Tabs.jsx b/src/shared/components/Contentful/Tabs/Tabs.jsx index c4f790cc08..f107392203 100644 --- a/src/shared/components/Contentful/Tabs/Tabs.jsx +++ b/src/shared/components/Contentful/Tabs/Tabs.jsx @@ -17,11 +17,13 @@ import { TabPanel, } from 'react-tabs'; import { fixStyle } from 'utils/contentful'; +import { getQuery, updateQuery } from 'utils/url'; import defaultTheme from './themes/style.scss'; import zurichTheme from './themes/zurich.scss'; import tabsGroup from './themes/tabsGroup.scss'; import tabsGroupChildren from './themes/tabsGroupChildren.scss'; import underlineTheme from './themes/underline.scss'; +import underlineDarkTheme from './themes/underline-dark.scss'; import verticalTheme from './themes/vertical.scss'; import pillsTheme from './themes/pills.scss'; @@ -31,6 +33,7 @@ export const TAB_THEMES = { 'Tabs Group': tabsGroup, 'Tabs Group Children': tabsGroupChildren, Underline: underlineTheme, + 'Underline dark': underlineDarkTheme, Vertical: verticalTheme, Pills: pillsTheme, }; @@ -38,7 +41,38 @@ export const TAB_THEMES = { export default class TabsItemsLoader extends Component { constructor(props) { super(props); - this.state = { tabIndex: props.selected }; + this.state = { + tabIndex: props.selected || 0, + }; + + this.updatePageUrl.bind(this); + } + + componentDidMount() { + const q = getQuery(); + const { tabId } = this.props; + const { tabIndex } = this.state; + if (q.tabs && q.tabs[tabId] && Number(q.tabs[tabId]) !== tabIndex) { + this.setState({ tabIndex: Number(q.tabs[tabId]) }); + } else { + this.updatePageUrl(); + } + } + + componentDidUpdate() { + this.updatePageUrl(); + } + + updatePageUrl() { + const q = getQuery(); + const { tabId } = this.props; + const { tabIndex } = this.state; + updateQuery({ + tabs: { + ...q.tabs, + [tabId]: tabIndex || 0, + }, + }); } render() { @@ -48,6 +82,7 @@ export default class TabsItemsLoader extends Component { spaceName, environment, theme, + tabId, } = this.props; const { tabIndex } = this.state; @@ -127,6 +162,7 @@ export default class TabsItemsLoader extends Component { environment={environment} selected={fields.selected} theme={TAB_THEMES[fields.theme || 'Default']} + tabId={tabId} /> ); } @@ -171,4 +207,5 @@ TabsItemsLoader.propTypes = { environment: PT.string, selected: PT.number, theme: PT.shape().isRequired, + tabId: PT.string.isRequired, }; diff --git a/src/shared/components/Contentful/Tabs/index.jsx b/src/shared/components/Contentful/Tabs/index.jsx index a109794431..cda003fb7f 100644 --- a/src/shared/components/Contentful/Tabs/index.jsx +++ b/src/shared/components/Contentful/Tabs/index.jsx @@ -34,6 +34,7 @@ function ContentfulTabs(props) { environment={environment} selected={fields.selected} theme={TAB_THEMES[fields.theme || 'Default']} + tabId={fields.urlQueryName || id} /> ); }} diff --git a/src/shared/components/Contentful/Tabs/themes/underline-dark.scss b/src/shared/components/Contentful/Tabs/themes/underline-dark.scss new file mode 100644 index 0000000000..65ec122112 --- /dev/null +++ b/src/shared/components/Contentful/Tabs/themes/underline-dark.scss @@ -0,0 +1,101 @@ +@import "~styles/mixins"; + +$container-background-gray: #ebebeb; +$text-color-black: #262628; +$text-color-gray: #888894; +$text-color-pannel: #4a4a4a; + +.container { + @include roboto-regular; + + max-width: $screen-md; + margin: auto; +} + +.tablist { + @include roboto-regular; + + display: -webkit-flex; /* Safari */ + display: flex; + -webkit-flex-direction: row; /* Safari */ + flex-direction: row; + -webkit-justify-content: center; /* Safari */ + justify-content: center; + list-style-type: none; + border-bottom: 5px solid #013b4d; + + @include xs-to-sm { + overflow-x: auto; + white-space: nowrap; + border: none; + margin-left: 16px; + } + + @media (max-width: 425px) { + justify-content: space-between; + } +} + +.tab { + text-align: center; + margin: 0 25px; + color: #fff; + font-size: 20px; + font-weight: 400; + line-height: 25px; + padding-bottom: 15px; + cursor: pointer; + margin-bottom: -5px; + position: relative; + + @include xs-to-sm { + margin: 0; + padding-right: 36px; + border-bottom: 5px solid #013b4d; + } + + &:hover, + &.selected { + &::after { + content: ''; + border-radius: 1000vw; + background: #43d7b0; + height: 5px; + width: 100%; + position: absolute; + bottom: 0; + left: 0; + + @include xs-to-sm { + width: calc(100% - 36px); + bottom: -5px; + } + } + } + + p { + small { + color: #888894; + font-size: 13px; + font-weight: 400; + line-height: 25px; + text-align: left; + } + + strong { + font-weight: bold; + } + } +} + +.tabpannel { + display: none; +} + +.selectedTabPanel { + display: block; + + @include xs-to-sm { + padding: 0 15px; + } +} diff --git a/src/shared/components/Contentful/Tabs/themes/underline.scss b/src/shared/components/Contentful/Tabs/themes/underline.scss index 9c014b07d6..5dc5689b77 100644 --- a/src/shared/components/Contentful/Tabs/themes/underline.scss +++ b/src/shared/components/Contentful/Tabs/themes/underline.scss @@ -25,31 +25,54 @@ $text-color-pannel: #4a4a4a; border-bottom: 5px solid #e9e9e9; @include xs-to-sm { - -webkit-flex-direction: column; /* Safari */ - flex-direction: column; - align-items: center; + overflow-x: auto; + white-space: nowrap; + border: none; + margin-left: 16px; + } + + @media (max-width: 425px) { + justify-content: space-between; } } .tab { text-align: center; - margin: 0 20px; - color: $text-color-black; + margin: 0 25px; + color: #2a2a2a; font-size: 20px; font-weight: 400; line-height: 25px; padding-bottom: 15px; cursor: pointer; margin-bottom: -5px; + position: relative; @include xs-to-sm { - margin: 2px; + margin: 0; + padding-right: 36px; + border-bottom: 5px solid #e9e9e9; } &:hover, &.selected { - border-bottom: 5px solid #43d7b0; - border-radius: 3px; + &::after { + content: ''; + border-radius: 1000vw; + background: #43d7b0; + height: 5px; + width: 100%; + position: absolute; + bottom: 0; + left: 0; + border-left: 1px solid #fff; + border-right: 1px solid #fff; + + @include xs-to-sm { + width: calc(100% - 36px); + bottom: -5px; + } + } } p { @@ -73,4 +96,8 @@ $text-color-pannel: #4a4a4a; .selectedTabPanel { display: block; + + @include xs-to-sm { + padding: 0 15px; + } } diff --git a/src/shared/components/Contentful/TracksTree/TracksTree.jsx b/src/shared/components/Contentful/TracksTree/TracksTree.jsx index 28039955bf..3e780482d2 100644 --- a/src/shared/components/Contentful/TracksTree/TracksTree.jsx +++ b/src/shared/components/Contentful/TracksTree/TracksTree.jsx @@ -6,7 +6,7 @@ import _ from 'lodash'; import PT from 'prop-types'; import React, { Component } from 'react'; import { themr } from 'react-css-super-themr'; -import { config } from 'topcoder-react-utils'; +import { config, Link } from 'topcoder-react-utils'; import IconArrowUpBig from 'assets/images/tc-edu/icon-arrow-up-big.svg'; import defaultTheme from './themes/default.scss'; @@ -57,7 +57,7 @@ export class TracksTreeInner extends Component { const selectedTrack = _.find(list, { id: expandedTrack }); return (
- THRIVE + THRIVE {!isShowFullList && selectedTrack && ( @@ -86,8 +88,8 @@ class ChallengeHistoryModal extends Component { @@ -112,19 +114,19 @@ class ChallengeHistoryModal extends Component { { challengesOrdered.map(challenge => ( - + - - {challenge.challenge_name || challenge.challenge_id} + + {challenge['challenge.challenge_name'] || challenge['tco_leaderboard.challenge_id'] || challenge.challenge_id} { !isCopilot ? ( - {challenge.place} + {challenge['tco_leaderboard.placement'] || challenge.place} ) : null } - {challenge.points} + {challenge['tco_leaderboard.tco_points'] || challenge.points} )) diff --git a/src/shared/components/Leaderboard/LeaderboardTable/index.jsx b/src/shared/components/Leaderboard/LeaderboardTable/index.jsx index 2f969a9ce4..33c49b62e9 100644 --- a/src/shared/components/Leaderboard/LeaderboardTable/index.jsx +++ b/src/shared/components/Leaderboard/LeaderboardTable/index.jsx @@ -28,6 +28,8 @@ import PT from 'prop-types'; import { Avatar } from 'topcoder-react-ui-kit'; import { config } from 'topcoder-react-utils'; import _ from 'lodash'; +import DefaultAvatar from 'assets/images/default-avatar-photo.svg'; + import avatarStyles from '../avatarStyles.scss'; import defaultStyles from './themes/styles.scss'; // eslint-disable-line @@ -58,7 +60,7 @@ export default function LeaderboardTable(props) { const stylesName = THEME[themeName]; const renderTableRows = comps => ( comps.map((competitor) => { - let photoUrl = competitor.avatar; + let photoUrl = competitor['member_profile_basic.photo_url'] || competitor.avatar; if (photoUrl) { photoUrl = `${config.CDN.PUBLIC}/avatar/${ encodeURIComponent(photoUrl)}?size=40`; @@ -68,12 +70,16 @@ export default function LeaderboardTable(props) { {competitor.rank} - + { + photoUrl ? ( + + ) : + } @@ -83,18 +89,18 @@ export default function LeaderboardTable(props) { styleName={`${stylesName}.handle-link`} onClick={() => onUsernameClick(competitor)} > - {competitor.handle} + {competitor['member_profile_basic.handle'] || competitor.handle}
) : ( - - {competitor.handle} + + {competitor['member_profile_basic.handle'] || competitor.handle} ) }
{competitor.fulfillment && ({competitor.fulfillment} fulfillment)} - {competitor.points} points - {competitor.challengecount} challenges + {competitor['tco_leaderboard.tco_points'] || competitor.points} points + {competitor['tco_leaderboard.challenge_count'] || competitor.challengecount} challenges
{ @@ -102,8 +108,8 @@ export default function LeaderboardTable(props) { {competitor.fulfillment} ) : null } - {competitor.challengecount} - {formatPoints(competitor.points)} + {competitor['tco_leaderboard.challenge_count'] || competitor.challengecount} + {formatPoints(competitor['tco_leaderboard.tco_points'] || competitor.points)} { isTopGear ? ( {competitor.wins} diff --git a/src/shared/components/Leaderboard/LeaderboardTable/themes/tco20.scss b/src/shared/components/Leaderboard/LeaderboardTable/themes/tco20.scss index fe4938c6b1..a77a4a8e4a 100644 --- a/src/shared/components/Leaderboard/LeaderboardTable/themes/tco20.scss +++ b/src/shared/components/Leaderboard/LeaderboardTable/themes/tco20.scss @@ -118,6 +118,11 @@ $table-bg-hover: #f5f5f5; height: 40px; width: 40px; overflow: hidden; + + svg { + border: 3px solid rgba(0, 0, 0, 0.05); + border-radius: 50%; + } } .col-handle { diff --git a/src/shared/components/Leaderboard/PodiumSpot/index.jsx b/src/shared/components/Leaderboard/PodiumSpot/index.jsx index 8a357fb00b..72fc4869d8 100644 --- a/src/shared/components/Leaderboard/PodiumSpot/index.jsx +++ b/src/shared/components/Leaderboard/PodiumSpot/index.jsx @@ -29,6 +29,7 @@ import PT from 'prop-types'; import { Avatar } from 'topcoder-react-ui-kit'; import { config } from 'topcoder-react-utils'; import _ from 'lodash'; +import DefaultAvatar from 'assets/images/default-avatar-photo.svg'; import avatarStyles from '../avatarStyles.scss'; import defaultStyles from './themes/styles.scss'; // eslint-disable-line @@ -99,7 +100,7 @@ export default function PodiumSpot(props) { } = props; const stylesName = THEME[themeName]; - let photoUrl = competitor.avatar; + let photoUrl = competitor['member_profile_basic.photo_url'] || competitor.avatar; if (photoUrl) { photoUrl = `${config.CDN.PUBLIC}/avatar/${ encodeURIComponent(photoUrl)}?size=160`; @@ -110,12 +111,16 @@ export default function PodiumSpot(props) { return (
- + { + photoUrl ? ( + + ) : + }
{DISPLAY_RANKING[competitor.rank]}
{ @@ -127,15 +132,15 @@ export default function PodiumSpot(props) { styleName={`${stylesName}.handle-link`} onClick={() => onUsernameClick(competitor)} > - {competitor.handle} + {competitor['member_profile_basic.handle'] || competitor.handle}
) : ( - {competitor.handle} + {competitor['member_profile_basic.handle'] || competitor.handle} ) } @@ -152,15 +157,15 @@ export default function PodiumSpot(props) { styleName={`${stylesName}.handle-link`} onClick={() => onUsernameClick(competitor)} > - {competitor.handle} + {competitor['member_profile_basic.handle'] || competitor.handle}
) : ( - {competitor.handle} + {competitor['member_profile_basic.handle'] || competitor.handle} ) } @@ -176,11 +181,11 @@ export default function PodiumSpot(props) { ) : null }
- {competitor.challengecount} + {competitor['tco_leaderboard.challenge_count'] || competitor.challengecount} challenges
- {formatPoints(competitor.points)} + {formatPoints(competitor['tco_leaderboard.tco_points'] || competitor.points)} points
{ diff --git a/src/shared/components/MarkdownRenderer/index.jsx b/src/shared/components/MarkdownRenderer/index.jsx index 195049e907..06aa09768a 100644 --- a/src/shared/components/MarkdownRenderer/index.jsx +++ b/src/shared/components/MarkdownRenderer/index.jsx @@ -5,12 +5,14 @@ * * Support for additional components can be added to the above file. */ +import _ from 'lodash'; import PT from 'prop-types'; import React, { Fragment } from 'react'; +import { connect } from 'react-redux'; import md from 'utils/markdown'; -export default class MarkdownRenderer extends React.Component { +class MarkdownRenderer extends React.Component { constructor(props) { super(props); this.state = { @@ -31,10 +33,17 @@ export default class MarkdownRenderer extends React.Component { } renderElements(markdown) { - const { preview, spaceName, environment } = this.props; + const { + preview, + spaceName, + environment, + profile, + } = this.props; if (markdown) { + const compiled = _.template(markdown, { variable: 'profile' }); + const interpolated = compiled(profile); this.setState({ - elements: md(markdown, { preview, spaceName, environment }), + elements: md(interpolated, { preview, spaceName, environment }), }); } } @@ -58,6 +67,7 @@ MarkdownRenderer.defaultProps = { preview: false, spaceName: null, environment: null, + profile: {}, }; MarkdownRenderer.propTypes = { @@ -65,4 +75,16 @@ MarkdownRenderer.propTypes = { preview: PT.bool, spaceName: PT.string, environment: PT.string, + profile: PT.shape(), }; + +function mapStateToProps(state) { + const profile = state.auth && state.auth.profile ? { ...state.auth.profile } : {}; + return { profile }; +} + +const MarkdownRendererContainer = connect( + mapStateToProps, +)(MarkdownRenderer); + +export default MarkdownRendererContainer; diff --git a/src/shared/components/PolicyPages/index.jsx b/src/shared/components/PolicyPages/index.jsx new file mode 100644 index 0000000000..8d3c20d2f7 --- /dev/null +++ b/src/shared/components/PolicyPages/index.jsx @@ -0,0 +1,114 @@ +/** + * PolicyPages component. + */ +import _ from 'lodash'; +import React, { useState, useEffect } from 'react'; +import PT from 'prop-types'; +import Sticky from 'react-stickynode'; +import { config, Link, isomorphy } from 'topcoder-react-utils'; +import cn from 'classnames'; +import ContentBlock from 'components/Contentful/ContentBlock'; +import Error404 from 'components/Error404'; +import MediaQuery from 'react-responsive'; +import './styles.scss'; + +const menuItems = (policyDataMenu, slug) => _.map(policyDataMenu, item => ( +
  • + {item.menuLinkText} +
  • +)); + +function PolicyPages({ + match, + policyData, +}) { + const [mNavi, setMNavi] = useState({ policies: false, legal: false }); + + function handeSectionClick() { + setMNavi({ + policies: this === 'policies', legal: this === 'legal', + }); + } + // auto scroll to anchors + useEffect(() => { + if (isomorphy.isClientSide()) { + const { hash } = window.location; + setTimeout(() => { + const anchor = document.getElementById(hash ? hash.slice(1) : null); + if (anchor) { + anchor.scrollIntoView({ behavior: 'smooth', block: 'start', inline: 'nearest' }); + } + }, 2000); + } + }); + + let { slug } = match.params; + const pages = policyData.Policies.concat(policyData.Legal); + if (!slug) { + // eslint-disable-next-line prefer-destructuring + slug = pages[0].slug; + } + const policyPage = _.find(pages, { slug }); + return ( +
    + + +
    +

    Policies

    +
      {menuItems(policyData.Policies, slug)}
    +

    Legal

    +
      {menuItems(policyData.Legal, slug)}
    +
    +
    +
    + +
    +
    + Policies +
    +
      + {menuItems(policyData.Policies, slug)} +
    +
    + Legal +
    +
      + {menuItems(policyData.Legal, slug)} +
    +
    +
    +
    + { + slug && !policyPage ? ( + + ) : ( + + ) + } +
    +
    + ); +} + +PolicyPages.propTypes = { + match: PT.shape().isRequired, + policyData: PT.shape().isRequired, +}; + +export default PolicyPages; diff --git a/src/shared/components/PolicyPages/styles.scss b/src/shared/components/PolicyPages/styles.scss new file mode 100644 index 0000000000..afca09b5cf --- /dev/null +++ b/src/shared/components/PolicyPages/styles.scss @@ -0,0 +1,147 @@ +@import '~styles/mixins'; + +.policy-pages-container { + position: relative; + max-width: $screen-md; + margin: 130px auto 200px auto; + display: grid; + grid-template-columns: 300px 1fr; + + @include xs-to-md { + display: flex; + flex-direction: column; + margin-top: 0; + } + + .navi { + display: flex; + flex-direction: column; + width: 200px; + margin-right: 85px; + padding-left: 15px; + padding-top: 15px; + + @include xs-to-md { + width: 100%; + background: white; + border-bottom: 1px solid #e0e0e0; + } + + .navi-section-title, + .navi-section-title2 { + text-transform: uppercase; + color: #2a2a2a; + font-family: Barlow, sans-serif; + font-size: 20px; + font-weight: 600; + line-height: 24px; + margin-bottom: 15px; + + @include xs-to-md { + margin-bottom: 5px; + } + } + + .navi-section-title2 { + margin-top: 42px; + + @include xs-to-md { + margin-top: 12px; + } + } + + .navi-section { + list-style: none; + + li { + a { + color: #2a2a2a; + font-family: Roboto, sans-serif; + font-size: 16px; + font-weight: 400; + line-height: 38px; + + &:hover { + font-weight: 700; + } + } + + &.active { + a { + font-weight: 700; + } + } + } + } + } + + .mobile-navi { + margin-bottom: 30px; + + .mobile-navi-section-title { + color: #2a2a2a; + font-family: Barlow, sans-serif; + font-size: 18px; + line-height: 24px; + text-transform: uppercase; + font-weight: 600; + padding: 15px; + border-bottom: 1px solid #e0e0e0; + outline: none; + + &::before { + display: inline-block; + content: ''; + height: 13px; + width: 13px; + margin-right: 11px; + border-bottom: 3px solid #aaa; + border-right: 3px solid #aaa; + transform: rotate(-45deg); + } + + &.active { + &::before { + transform: rotate(45deg); + } + } + } + + .mobile-navi-section { + list-style: none; + display: none; + padding-top: 17px; + + &.active { + display: block; + border-bottom: 1px solid #e0e0e0; + } + + li { + padding-left: 40px; + font-family: Roboto, sans-serif; + margin-bottom: 24px; + + &:last-child { + margin-bottom: 15px; + } + + &.active { + border-left: 3px solid #43d7b0; + border-radius: 1.5px; + padding-left: 37px; + + a { + font-weight: 700; + line-height: 26px; + } + } + } + } + } + + .page-content { + min-height: 100vh; + flex: 1; + } +} diff --git a/src/shared/components/SubmissionManagement/Submission/index.jsx b/src/shared/components/SubmissionManagement/Submission/index.jsx index dc248e1a05..c2f6c8816e 100644 --- a/src/shared/components/SubmissionManagement/Submission/index.jsx +++ b/src/shared/components/SubmissionManagement/Submission/index.jsx @@ -15,6 +15,7 @@ import _ from 'lodash'; import moment from 'moment'; import React from 'react'; import { config } from 'topcoder-react-utils'; +import { COMPETITION_TRACKS } from 'utils/tc'; import PT from 'prop-types'; @@ -49,7 +50,7 @@ export default function Submission(props) { {formatDate(submissionObject.created)} { - track === 'Design' && ( + track === COMPETITION_TRACKS.DESIGN && ( {submissionObject.screening && ( @@ -66,7 +67,7 @@ export default function Submission(props) {
    - { track === 'DEVELOP' ? ( + { track === COMPETITION_TRACKS.DEVELOP ? (
    {isChallengeBelongToTopgearGroup ? (

    Enter the URL to your submission.

    ) : (

    Upload your entire submission as a single zip file.

    )}
    ) : null } - { track === 'DESIGN' ? ( + { track === COMPETITION_TRACKS.DESIGN ? (
    1. Place your submission files into a "Submission.zip" file.
    2. diff --git a/src/shared/components/SubmissionPage/Uploading/index.jsx b/src/shared/components/SubmissionPage/Uploading/index.jsx index dac34c4b03..600fbca5ba 100644 --- a/src/shared/components/SubmissionPage/Uploading/index.jsx +++ b/src/shared/components/SubmissionPage/Uploading/index.jsx @@ -14,6 +14,8 @@ import RobotSad from 'assets/images/robot-embarassed.svg'; import { PrimaryButton, Button } from 'topcoder-react-ui-kit'; import './styles.scss'; +import { COMPETITION_TRACKS } from 'utils/tc'; + const Uploading = ({ challengeId, challengeName, @@ -156,7 +158,7 @@ const Uploading = ({ submitDone && !error && (
      - { track === 'DESIGN' ? ( + { track === COMPETITION_TRACKS.DESIGN ? (
      diff --git a/src/shared/components/challenge-detail/Header/TabSelector/index.jsx b/src/shared/components/challenge-detail/Header/TabSelector/index.jsx index 10956b9151..98df8985c4 100644 --- a/src/shared/components/challenge-detail/Header/TabSelector/index.jsx +++ b/src/shared/components/challenge-detail/Header/TabSelector/index.jsx @@ -34,6 +34,7 @@ export default function ChallengeViewSelector(props) { mySubmissions, } = props; + const numOfSub = numOfSubmissions + (numOfCheckpointSubmissions || 0); const forumId = _.get(challenge, 'legacy.forumId') || 0; const roles = _.get(challenge, 'userDetails.roles') || []; const isDesign = trackLower === 'design'; @@ -125,7 +126,7 @@ export default function ChallengeViewSelector(props) { ) } { - (numOfSubmissions && isLoggedIn) ? ( + (numOfSub && isLoggedIn) ? ( SUBMISSIONS ( - {numOfSubmissions + (numOfCheckpointSubmissions || 0)} + {numOfSub} ) ) : null diff --git a/src/shared/components/challenge-detail/Header/index.jsx b/src/shared/components/challenge-detail/Header/index.jsx index 28672781e1..0a6594ea8f 100644 --- a/src/shared/components/challenge-detail/Header/index.jsx +++ b/src/shared/components/challenge-detail/Header/index.jsx @@ -14,6 +14,7 @@ import PT from 'prop-types'; import React from 'react'; import { DangerButton, PrimaryButton } from 'topcoder-react-ui-kit'; import { Link } from 'topcoder-react-utils'; +import { COMPETITION_TRACKS } from 'utils/tc'; import LeftArrow from 'assets/images/arrow-prev.svg'; @@ -385,7 +386,7 @@ export default function ChallengeHeader(props) { Submit { - track === 'DESIGN' && hasRegistered && !unregistering + track === COMPETITION_TRACKS.DESIGN && hasRegistered && !unregistering && hasSubmissions && ( p.name !== 'Registration' && p.isOpen) .sort((a, b) => moment(a.scheduledEndDate).diff(b.scheduledEndDate))[0]; - if (!statusPhase && subTrack === 'FIRST_2_FINISH' && allPhases.length) { + if (!statusPhase && type === 'First2Finish' && allPhases.length) { statusPhase = _.clone(allPhases[0]); statusPhase.name = 'Submission'; } diff --git a/src/shared/components/tc-communities/communities/wipro/FAQ/index.jsx b/src/shared/components/tc-communities/communities/wipro/FAQ/index.jsx deleted file mode 100644 index 622fe7056f..0000000000 --- a/src/shared/components/tc-communities/communities/wipro/FAQ/index.jsx +++ /dev/null @@ -1,305 +0,0 @@ -/** - * Static implementation of Learn page for Wipro 2 community - * - * It hardcodes data which is passed to dummy components, - * thus we disable max-len eslint rule for this file - */ -/* eslint-disable max-len */ - -import React from 'react'; -// import { Link } from 'react-router-dom'; -import Section from 'components/tc-communities/Section'; -import VideoCard from 'components/tc-communities/VideoCard'; -/* -import Accordion from 'components/tc-communities/Accordion/Accordion'; -import AccordionItem from 'components/tc-communities/Accordion/AccordionItem'; -*/ -import Banner from 'components/tc-communities/Banner'; -/* -import NewsletterSignup from 'components/tc-communities/NewsletterSignup'; -import ArticleCard from 'components/tc-communities/ArticleCard'; -import LinksCard from 'components/tc-communities/LinksCard'; -import Text from 'components/tc-communities/Text'; -*/ - -import Accordion from 'components/tc-communities/Accordion/Accordion'; -import AccordionItem from 'components/tc-communities/Accordion/AccordionItem'; -import Text from 'components/tc-communities/Text'; -import { ThemeProvider } from 'react-css-super-themr'; - -import theme from '../theme'; -import style from './style.scss'; - -export default function Learn() { - return ( - -
      - -
      - - - - - -
      -
      - - - -

      - If you are new to Topcoder challenges, learn more about the overall concepts of challenges by watching this - - video - - . -

      -
      -
      - - -

      - Follow the instructions in this - - video - - . -

      -
      -
      - - -

      - Find a challenge that interests you on the - - challenge listings page - - . You can filter by challenge types, prizes, deadlines, etc. Look for challenges that are still open for registration. If you see something that interests you, click it and then you can read the details and register for the challenge. Watch the - - video - - . -

      -
      -
      - - -

      - Do all of your coding/design work offline, or as specified in the challenge spec. When you are ready to submit, come back to the challenge page and click the Submit button. The Submit page will give instructions to upload your submission. Watch the - - video - - . -

      -
      -
      - - -

      - If you are a reviewer or copilot and need information about managing projects and challenges, please visit the - - Help Center - - . -

      -
      -
      - - -

      - No role restrictions or band restrictions for participating in challenges. -

      -
      -
      - - -

      - In Home page click on Challenges; Look for challenges that are still open for registration. Click on the Challenge to see skills/technology involved and other details; Register to participate in the challenge OR go through video -

      -
      -
      - - -

      - Yes you can participate in more than one challenge simultaneously -

      -
      -
      - - -

      - Each challenge details will have details about winner prize and TopGear points associated -

      -
      -
      - - -

      - You can use Challenge Forum to get clarifications for your queries -

      -
      -
      - - -

      - On the Home page click on Learning; Navigate to communities to see skills available on platform. -

      -
      -
      - - -

      - In Home page click on Learning; Navigate to communities; Join a community where you want to enhance your skills; Join training/case study projects and complete the same. -

      -
      -
      - - -

      - Yes. The resume gets updated automatically after approval of submissions corresponding to training/case study and challenge. -

      -
      -
      - - -

      - No. Contribution time in participating will not be considered for over-time benefits. -

      -
      -
      - - -

      - TopGear points can be earned by completing training/case study projects and by participating and submitting qualified submission in a challenge. -

      -
      -
      - - -

      - TopGear points accumulated by the employees after redemption post periodic contest/promotion shall be valid till the last working day of the employee. Beyond this period the points shall lapse. -

      -
      -
      - - -

      - No, the reward points cannot be exchanged for any other benefits. -

      -
      -
      - - -

      - If you are eligible for periodic contest – spot awards and you are exiting prior to contest/promotion scheduled date, the points get lapsed. -

      -
      -
      - - -

      - TopGear contribution credits are considered under Organization Contribution category of TrendNxt. -

      -
      -
      - - -

      - TopGear points earned may be considered for periodic contests. -

      -
      -
      - - -

      - TopGear points earned may be considered for periodic contests. -

      -
      -
      - - -

      - Send a mail to ask.topgear@wipro.com and TopGear team will get back to you with details and process. -

      -
      -
      - - -

      - Send a mail to ask.topgear@wipro.com and TopGear team will get back to you with details. a. User could also register on link - ‌ - - https://topgear-app.wipro.com/topcoder_reviewer/registration - -

      -
      -
      - - -

      - On Home Page select ‘Initiate Project’ and provide initial information about projects OR send a mail to ask.topgear@wipro.com and TopGear team will get back to you with details OR go through video. -

      -
      -
      - - -

      - Submit a request at - - https://help.topcoder.com/hc/en-us/requests/new?ticket_form_id=779747 - - {' '} - and a TopGear team member will help get it setup. -

      -
      -
      - - -

      - Please write to ask.topgear@wipro.com -

      -
      -
      -
      -
      - -
      -
      - ); -} diff --git a/src/shared/components/tc-communities/communities/wipro/FAQ/style.scss b/src/shared/components/tc-communities/communities/wipro/FAQ/style.scss deleted file mode 100644 index 66f8df0f29..0000000000 --- a/src/shared/components/tc-communities/communities/wipro/FAQ/style.scss +++ /dev/null @@ -1,151 +0,0 @@ -@import '~styles/mixins'; - -.continueButton { - display: block; - margin: auto; -} - -.coursesContainer { - padding-bottom: 60px; -} - -.faqContainer { - padding-top: 0; -} - -.faqTitle { - padding-top: 0; -} - -.highlighted { - background: #ffc; -} - -.ddashUnderline { - border-bottom: 1px dashed #333; -} - -.resourcesTitle { - padding-bottom: 50px; - padding-top: 0; - - @include xs-to-sm { - font-size: 36px; - padding-bottom: 30px; - } -} - -.resourcesContainer { - padding-bottom: 60px; - - @include xs-to-sm { - padding-bottom: 50px; - } -} - -.bannerContainer { - height: 252px; - - @include xs-to-sm { - height: 300px; - } -} - -.bannerContent { - bottom: 0; - top: 0; - transform: none; - width: 600px; - - @include xs-to-sm { - top: auto; - width: 100%; - } -} - -.bannerContentInner { - @include xs-to-sm { - padding-bottom: 20px; - padding-top: 48px; - } -} - -.learnBasicsContainer { - padding-bottom: 0; -} - -.joinnowWrap { - margin-top: 10px; - - @include xs-to-sm { - margin-top: 20px; - text-align: center; - } -} - -.joinnow { - color: #0092ff; - display: inline-block; - border: 1px solid #0092ff; - border-radius: 20px; - font: 700 14px/40px 'Open Sans', sans-serif; - height: 40px; - text-align: center; - text-transform: uppercase; - width: 171px; - - &:hover, - &:active, - &:focus, - &:visited { - color: #0092ff; - outline: none; - text-decoration: none; - } -} - -.message { - color: #333; - font: 16px/22px 'Akkurat regular', sans-serif; - opacity: 0.7; - - a { - &, - &:hover, - &:active, - &:focus, - &:visited { - color: #0092ff; - font-family: 'Times New Roman', Times, serif; - outline: none; - text-decoration: underline; - } - } - - em { - font-family: 'Times New Roman', Times, serif; - font-style: italic; - } - - ol { - list-style: decimal inside; - padding-left: 24px; - } - - p { - margin-bottom: 24px; - } - - strong { - font-weight: bold; - } -} - -.tutorialsTitle { - padding-top: 0; -} - -.tutorialsContent { - flex-wrap: wrap; - justify-content: center; -} diff --git a/src/shared/components/tc-communities/communities/wipro/Home/themes/articleCardStyles.scss b/src/shared/components/tc-communities/communities/wipro/Home/themes/articleCardStyles.scss deleted file mode 100644 index 34cc9d6bd6..0000000000 --- a/src/shared/components/tc-communities/communities/wipro/Home/themes/articleCardStyles.scss +++ /dev/null @@ -1,79 +0,0 @@ -@import '~styles/mixins'; - -.container { - background: rgba(#f2f2f2, 0.5); - border-radius: 0; - box-shadow: none; - border: 1px solid #00a2e0; - height: 400px; - width: 300px; - - @include md { - width: 220px; - } - - @include xs-to-sm { - height: auto; - margin: 0 15px; - padding-bottom: 30px; - width: auto; - - & + & { - margin-top: 30px; - } - } -} - -.image { - background: no-repeat center; - background-size: cover; - display: block; - height: 150px; - - @include xs-to-sm { - height: auto; - min-height: 205px; - - &::after { - content: ''; - display: block; - height: 0; - padding-bottom: 59.42%; /* fixed aspect ration 205 / 345 */ - } - } -} - -.content { - padding: 0 12px; - text-align: left; -} - -.title { - color: #00a2e0; - font-family: 'Akkurat mono', sans-serif; - font-weight: normal; - font-size: 16px; - text-decoration: underline; - margin-top: 10px; - max-height: 75px; - overflow: hidden; - text-overflow: ellipsis; - - @include md { - font-size: 16px; - } -} - -.text { - color: #333; - font-family: 'Akkurat regular', sans-serif; - font-size: 14px; - margin-top: 10px; - max-height: 84px; - overflow: hidden; - text-overflow: ellipsis; -} - -.linkWrap { - display: none; -} diff --git a/src/shared/components/tc-communities/communities/wipro/Home/themes/newsSectionStyles.scss b/src/shared/components/tc-communities/communities/wipro/Home/themes/newsSectionStyles.scss deleted file mode 100644 index 643a4638bb..0000000000 --- a/src/shared/components/tc-communities/communities/wipro/Home/themes/newsSectionStyles.scss +++ /dev/null @@ -1,18 +0,0 @@ -@import '~styles/mixins'; - -.container { - padding: 50px 0; - padding-bottom: 50px; -} - -.title { - color: #646363; - font-family: 'Akkurat bold', sans-serif; - font-size: 21px; - padding-top: 0; - - @include xs-to-sm { - font-size: 18px; - padding-top: 0; - } -} diff --git a/src/shared/components/tc-communities/communities/wipro/Home/themes/newsletter_signup.scss b/src/shared/components/tc-communities/communities/wipro/Home/themes/newsletter_signup.scss deleted file mode 100644 index c3e68c235b..0000000000 --- a/src/shared/components/tc-communities/communities/wipro/Home/themes/newsletter_signup.scss +++ /dev/null @@ -1,86 +0,0 @@ -@import '~styles/mixins'; - -.container { - height: 180px; - - &::before { - background-color: #f8f8f8; - } -} - -.content { - padding: 20px; -} - -.title { - color: #333; - font-family: 'Akkurat bold', sans-serif; - font-size: 21px; - - @include xs-to-sm { - font-size: 18px; - } -} - -.text { - color: #646363; - font-family: 'Akkurat bold', sans-serif; - font-size: 16px; - margin-top: 20px; -} - -.form { - display: inline-block; - margin-top: 20px; - overflow: visible; -} - -input:not([type="checkbox"]).formEmail { - background-color: #fff; - border: 1px solid #00a2e0; - border-radius: 40px; - border-bottom-right-radius: 0; - border-top-right-radius: 0; - color: #646363; - font-family: 'Akkurat light', sans-serif; - font-size: 16px; - line-height: 40px; - height: 40px; - - @include xs-to-sm { - width: 50%; - } - - @include placeholder { - color: #646363; - font-family: 'Akkurat light', sans-serif; - font-size: 16px; - line-height: 40px; - text-transform: none; - } - - &:hover, - &:active, - &:focus { - border: 1px solid #00a2e0; - } -} - -.formButton { - background: #00a2e0; - font-family: 'Akkurat regular', sans-serif; - font-size: 16px; - line-height: 40px; - color: #fff; - border: 0; - border-radius: 40px; - border-bottom-left-radius: 0; - border-top-left-radius: 0; - text-transform: none; - width: auto; - padding: 0 30px 0 20px; - - @include xs-to-sm { - width: 135px; - } -} diff --git a/src/shared/components/tc-communities/communities/wipro/Home/themes/resourceCardStyles.scss b/src/shared/components/tc-communities/communities/wipro/Home/themes/resourceCardStyles.scss deleted file mode 100644 index 46ec6a1835..0000000000 --- a/src/shared/components/tc-communities/communities/wipro/Home/themes/resourceCardStyles.scss +++ /dev/null @@ -1,84 +0,0 @@ -@import '~styles/mixins'; - -.container { - text-align: left; - width: 280px; - - @include md { - width: 200px; - } - - @include xs-to-sm { - padding: 0 15px; - width: auto; - - & + & { - padding-top: 50px; - } - } -} - -.icon { - display: none; -} - -.title { - font-family: 'Akkurat mono', sans-serif; - font-size: 16px; - color: #00a2e0; - margin-top: 0; - position: relative; - text-decoration: underline; - - &::before { - content: ''; - background-color: #00a2e0; - position: absolute; - width: 2px; - height: 70px; - left: -10px; - top: 0; - } - - @include xs-to-sm { - font-size: 16px; - } -} - -.text { - color: #333; - font-family: 'Akkurat regular', sans-serif; - font-size: 14px; - margin-top: 10px; -} - -.linkWrap { - margin-top: 30px; -} - -.link { - color: #00a2e0; - display: inline-block; - border: 1px solid #00a2e0; - border-radius: 40px; - font-family: 'Akkurat regular', sans-serif; - font-size: 16px; - height: 40px; - text-align: center; - text-transform: none; - min-width: 220px; - padding: 0 24px; - - &:hover, - &:active, - &:focus, - &:visited { - color: #00a2e0; - outline: none; - text-decoration: none; - } - - @include md { - width: 200px; - } -} diff --git a/src/shared/containers/EDU/partials/TrackCards.jsx b/src/shared/containers/EDU/partials/TrackCards.jsx index 7bf1805436..50f52334e0 100644 --- a/src/shared/containers/EDU/partials/TrackCards.jsx +++ b/src/shared/containers/EDU/partials/TrackCards.jsx @@ -13,7 +13,7 @@ export default function TrackCards(props) { content_type: 'article', 'fields.trackCategory': track, limit: 3, - order: 'sys.createdAt', + order: '-sys.createdAt', }} spaceName="EDU" render={(data) => { diff --git a/src/shared/containers/EDU/partials/TrackInfoInner.jsx b/src/shared/containers/EDU/partials/TrackInfoInner.jsx index 87ec321196..d576078ab1 100644 --- a/src/shared/containers/EDU/partials/TrackInfoInner.jsx +++ b/src/shared/containers/EDU/partials/TrackInfoInner.jsx @@ -1,22 +1,22 @@ import _ from 'lodash'; import React from 'react'; import PT from 'prop-types'; -import { config } from 'topcoder-react-utils'; +import { config, Link } from 'topcoder-react-utils'; import qs from 'qs'; export default function TrackInfoInner(props) { const { track, taxonomy, theme } = props; return (
      - + {track} - + { taxonomy[track] ? (
      { _.map( - _.sortBy(taxonomy[track], ['name']), tax => {tax.name}, + _.sortBy(taxonomy[track], ['name']), tax => {tax.name}, ) }
      diff --git a/src/shared/containers/Leaderboard/index.jsx b/src/shared/containers/Leaderboard/index.jsx index 1f6e9a8245..bb97062b91 100644 --- a/src/shared/containers/Leaderboard/index.jsx +++ b/src/shared/containers/Leaderboard/index.jsx @@ -10,7 +10,6 @@ import actions from 'actions/leaderboard'; import LeaderboardTable from 'components/Leaderboard/LeaderboardTable'; import Podium from 'components/Leaderboard/Podium'; import Banner from 'components/tc-communities/Banner'; -import NewsletterSignup from 'components/tc-communities/NewsletterSignup'; import style from './styles.scss'; @@ -59,11 +58,6 @@ class LeaderboardPageContainer extends React.Component {
      -
    ); } diff --git a/src/shared/containers/PolicyPages.jsx b/src/shared/containers/PolicyPages.jsx new file mode 100644 index 0000000000..3f2336cc49 --- /dev/null +++ b/src/shared/containers/PolicyPages.jsx @@ -0,0 +1,86 @@ +/** + * Connects the Redux store to the PolicyPages component. + */ +import _ from 'lodash'; +import React from 'react'; +import { connect } from 'react-redux'; +import PT from 'prop-types'; +import actions from 'actions/contentful'; +import PolicyPages from 'components/PolicyPages'; +import LoadingIndicator from 'components/LoadingIndicator'; +import Header from 'containers/TopcoderHeader'; +import Footer from 'components/TopcoderFooter'; + +const HEADE_MENU = [ + { + id: 'business', + title: 'BUSINESS', + href: 'https://www.topcoder.com', + }, + { + id: 'community-123', + title: 'COMMUNITY', + href: '/community/learn', + }, +]; + +class PolicyPagesContainer extends React.Component { + componentDidMount() { + const { loadingPolicyPages, policyData, getPolicyPages } = this.props; + if (!loadingPolicyPages && !policyData) { + getPolicyPages(); + } + } + + render() { + const { + loadingPolicyPages, policyData, + } = this.props; + if (loadingPolicyPages || !policyData) return ; + if (_.isEmpty(policyData)) { + return ( +

    Please, publish Policy Pages in Contentful space to see this page.

    + ); + } + return ( +
    +
    + +
    +
    + ); + } +} + +PolicyPagesContainer.defaultProps = { + loadingPolicyPages: false, + policyData: null, +}; + +PolicyPagesContainer.propTypes = { + loadingPolicyPages: PT.bool, + match: PT.shape().isRequired, + policyData: PT.shape(), + getPolicyPages: PT.func.isRequired, +}; + +function mapStateToProps(state, ownProps) { + return { + p: ownProps.p, + policyData: state.policyPages.policyData, + }; +} + +function mapDispatchToProps(dispatch) { + return { + getPolicyPages: () => { + dispatch(actions.contentful.getPolicyPagesInit()); + dispatch(actions.contentful.getPolicyPagesDone()); + }, + }; +} + +export default connect( + mapStateToProps, + mapDispatchToProps, +)(PolicyPagesContainer); diff --git a/src/shared/containers/SubmissionPage.jsx b/src/shared/containers/SubmissionPage.jsx index 9fdfe47a78..da4e84aeba 100644 --- a/src/shared/containers/SubmissionPage.jsx +++ b/src/shared/containers/SubmissionPage.jsx @@ -174,7 +174,7 @@ const mapStateToProps = (state, ownProps) => { challengesUrl: ownProps.challengesUrl, tokenV2: state.auth.tokenV2, tokenV3: state.auth.tokenV3, - track: details.legacy ? details.legacy.track : '', + track: details.track, challenge: state.challenge, status: details.status, isRegistered: details.isRegistered, diff --git a/src/shared/containers/TopcoderHeader.js b/src/shared/containers/TopcoderHeader.js index 537372ed51..8303cf3c9b 100644 --- a/src/shared/containers/TopcoderHeader.js +++ b/src/shared/containers/TopcoderHeader.js @@ -38,7 +38,7 @@ function mapDispatchToProps(dispatch) { }; } -function mapStateToProps(state) { +function mapStateToProps(state, ownProps) { return { ...state.topcoderHeader, profile: { @@ -51,6 +51,7 @@ function mapStateToProps(state) { auth: { ...state.auth, }, + headerMenu: ownProps.headerMenu, }; } diff --git a/src/shared/containers/challenge-detail/index.jsx b/src/shared/containers/challenge-detail/index.jsx index dab60b189f..65cb2e339f 100644 --- a/src/shared/containers/challenge-detail/index.jsx +++ b/src/shared/containers/challenge-detail/index.jsx @@ -32,7 +32,12 @@ import { connect } from 'react-redux'; import challengeDetailsActions, { TABS as DETAIL_TABS } from 'actions/page/challenge-details'; import { BUCKETS } from 'utils/challenge-listing/buckets'; -import { CHALLENGE_PHASE_TYPES, COMPETITION_TRACKS_V3, SUBTRACKS } from 'utils/tc'; +import { + CHALLENGE_PHASE_TYPES, + COMPETITION_TRACKS, + COMPETITION_TRACKS_V3, + SUBTRACKS, +} from 'utils/tc'; import { config, MetaTags } from 'topcoder-react-utils'; import { actions } from 'topcoder-react-lib'; import { getService } from 'services/contentful'; @@ -238,9 +243,8 @@ class ChallengeDetailPageContainer extends React.Component { reloadChallengeDetails(nextProps.auth, challengeId); } - const { legacy } = nextProps.challenge; - const track = legacy ? legacy.track : nextProps.challenge.track; - if (track && track.toLowerCase() !== 'design' && thriveArticles.length === 0) { + const { track } = nextProps.challenge; + if (track === COMPETITION_TRACKS.DESIGN && thriveArticles.length === 0) { // filter all tags with value 'Other' const tags = _.filter(nextProps.challenge.tags, tag => tag !== 'Other'); if (tags.length > 0) { @@ -840,7 +844,7 @@ const mapDispatchToProps = (dispatch) => { dispatch(a.getDetailsDone(challengeId, tokens.tokenV3, tokens.tokenV2)) .then((res) => { const ch = res.payload; - if (ch.legacy.track === 'DESIGN') { + if (ch.track === COMPETITION_TRACKS.DESIGN) { const p = ch.phases || [] .filter(x => x.name === 'Checkpoint Review'); if (p.length && !p[0].isOpen) { @@ -864,7 +868,7 @@ const mapDispatchToProps = (dispatch) => { const a = actions.challenge; dispatch(a.getDetailsDone(challengeId, tokens.tokenV3, tokens.tokenV2)) .then((challengeDetails) => { - if (challengeDetails.legacy.track === 'DESIGN') { + if (challengeDetails.track === COMPETITION_TRACKS.DESIGN) { const p = challengeDetails.phases || [] .filter(x => x.name === 'Checkpoint Review'); if (p.length && !p[0].isOpen) { diff --git a/src/shared/reducers/contentful/policyPages.jsx b/src/shared/reducers/contentful/policyPages.jsx new file mode 100644 index 0000000000..663c9418ab --- /dev/null +++ b/src/shared/reducers/contentful/policyPages.jsx @@ -0,0 +1,38 @@ +/** + * Reducer for state.policyPages + */ +import _ from 'lodash'; +import actions from 'actions/contentful'; +import { handleActions } from 'redux-actions'; + +function onGetPolicyPagesInit(state) { + return { + ...state, + loadingPolicyPages: true, + }; +} + +function onGetPolicyPagesDone(state, action) { + const policyData = _.groupBy(action.payload.data.map(pp => pp.fields), 'menuSection'); + return { + ...state, + loadingPolicyPages: false, + policyData, + }; +} + +/** + * Creates challengesBlock reducer with the specified initial state. + * @param {Object} state Optional. If not given, the default one is + * generated automatically. + * @return {Function} Reducer. + */ +function create(state = {}) { + return handleActions({ + [actions.contentful.getPolicyPagesInit]: onGetPolicyPagesInit, + [actions.contentful.getPolicyPagesDone]: onGetPolicyPagesDone, + }, state); +} + +/* Reducer with the default initial state. */ +export default create(); diff --git a/src/shared/reducers/index.js b/src/shared/reducers/index.js index 16a1ffd3fa..dac86033f4 100644 --- a/src/shared/reducers/index.js +++ b/src/shared/reducers/index.js @@ -27,6 +27,7 @@ import rss from './rss'; import newsletterArchive from './newsletterArchive'; import menuNavigation from './contentful/menuNavigation'; import challengesBlock from './contentful/challengesBlock'; +import policyPages from './contentful/policyPages'; import { factory as challengeListingFactory } from './challenge-listing'; import { factory as examplesFactory } from './examples'; import { factory as pageFactory } from './page'; @@ -137,6 +138,7 @@ export function factory(req) { newsletterArchive, menuNavigation, challengesBlock, + policyPages, newsletterPreferences, })); } diff --git a/src/shared/routes/Communities/Wipro/Routes.jsx b/src/shared/routes/Communities/Wipro/Routes.jsx index 5d0085087f..23ac24adc1 100644 --- a/src/shared/routes/Communities/Wipro/Routes.jsx +++ b/src/shared/routes/Communities/Wipro/Routes.jsx @@ -6,12 +6,8 @@ import ChallengeDetails from 'routes/ChallengeDetails'; import ChallengeListing from 'routes/Communities/ChallengeListing'; import ChallengeListingBanner from 'components/tc-communities/communities/wipro/ChallengeListingBanner'; import ContentfulRoute from 'components/Contentful/Route'; -import FAQ from 'components/tc-communities/communities/wipro/FAQ'; -import Footer from 'components/tc-communities/communities/wipro/Footer'; import Header from 'containers/tc-communities/Header'; -import Home from 'containers/tc-communities/wipro/Home'; import LeaderboardBanner from 'components/tc-communities/communities/wipro/LeaderboardBanner'; -import Learn from 'components/tc-communities/communities/wipro/Learn'; import PT from 'prop-types'; import React from 'react'; import Submission from 'routes/Submission'; @@ -20,6 +16,7 @@ import TermsDetail from 'routes/TermsDetail'; import Profile from 'routes/Profile'; import ProfileStats from 'routes/ProfileStats'; import Settings from 'routes/Settings'; +import Viewport from 'components/Contentful/Viewport'; import theme from 'components/tc-communities/communities/wipro/theme'; import { ThemeProvider } from 'react-css-super-themr'; import { Route, Switch } from 'react-router-dom'; @@ -105,11 +102,6 @@ export default function Wipro({ base, meta }) { exact path={`${base}/challenges/terms/detail/:termId`} /> - ( - - - -
    +
    )} diff --git a/src/shared/routes/PolicyPages.jsx b/src/shared/routes/PolicyPages.jsx new file mode 100644 index 0000000000..f03fec58f2 --- /dev/null +++ b/src/shared/routes/PolicyPages.jsx @@ -0,0 +1,21 @@ +/** + * The loader of Policy page webpack chunks. + */ +import React from 'react'; + +import LoadingPagePlaceholder from 'components/LoadingPagePlaceholder'; +import { AppChunk } from 'topcoder-react-utils'; + +export default function PolicyPagesRoute(props) { + return ( + import(/* webpackChunkName: "policyPages/chunk" */ 'containers/PolicyPages') + .then(({ default: PolicyPagesContainer }) => ( + + )) + } + renderPlaceholder={() => } + /> + ); +} diff --git a/src/shared/routes/index.jsx b/src/shared/routes/index.jsx index d8bd5d338d..04f1f6d25f 100644 --- a/src/shared/routes/index.jsx +++ b/src/shared/routes/index.jsx @@ -9,7 +9,7 @@ import React from 'react'; import { Switch, Route, withRouter, Redirect, } from 'react-router-dom'; -import { MetaTags } from 'topcoder-react-utils'; +import { MetaTags, config } from 'topcoder-react-utils'; import PT from 'prop-types'; @@ -22,6 +22,7 @@ import Examples from './Examples'; import Sandbox from './Sandbox'; import Topcoder from './Topcoder'; import TrackHomePages from './TrackHomePages'; +import PolicyPages from './PolicyPages'; function Routes({ communityId }) { const metaTags = ( @@ -54,7 +55,7 @@ function Routes({ communityId }) { {metaTags} - { Examples() } + {Examples()} ( } path="/community/(competitive-programming|data-science|design|development|qa)/how-to-compete" /> +
    diff --git a/src/shared/utils/contentful.js b/src/shared/utils/contentful.js index 3c253aa36b..a7b4880310 100644 --- a/src/shared/utils/contentful.js +++ b/src/shared/utils/contentful.js @@ -9,7 +9,14 @@ import { removeTrailingSlash } from 'utils/url'; * @return {Object} */ export function fixStyle(style) { - return style ? _.mapKeys(style, (value, key) => _.camelCase(key)) : undefined; + const props = _.omitBy(style, !_.isObject); + const mediaQueries = _.pickBy( + style, + (propVal, mQuery) => _.isObject(propVal) + && isomorphy.isClientSide() && window.matchMedia(mQuery).matches, + ); + const merged = _.merge(props, ..._.values(mediaQueries)); + return merged ? _.mapKeys(merged, (value, key) => _.camelCase(key)) : undefined; } // Concatenates a base and segment and handles optional trailing slashes diff --git a/src/shared/utils/url.js b/src/shared/utils/url.js index 73154aa74a..dc2a90d0ac 100644 --- a/src/shared/utils/url.js +++ b/src/shared/utils/url.js @@ -8,6 +8,22 @@ import _ from 'lodash'; import qs from 'qs'; import { isomorphy } from 'topcoder-react-utils'; +/** + * Get current URL hash parameters as object + */ +export function getHash() { + if (isomorphy.isServerSide()) return null; + return qs.parse(window.location.hash.slice(1)); +} + +/** + * Get current URL query parameters as object + */ +export function getQuery() { + if (isomorphy.isServerSide()) return {}; + return qs.parse(window.location.search.slice(1)); +} + /** * If executed client-side (determined in this case by the presence of global * window object), this function updates query section of URL; otherwise does @@ -22,6 +38,7 @@ export function updateQuery(update) { if (isomorphy.isServerSide()) return; let query = qs.parse(window.location.search.slice(1)); + const { hash } = window.location; /* _.merge won't work here, because it just ignores the fields explicitely * set as undefined in the objects to be merged, rather than deleting such @@ -31,6 +48,9 @@ export function updateQuery(update) { else query[key] = value; }); query = `?${qs.stringify(query, { encodeValuesOnly: true })}`; + if (hash) { + query += hash; + } window.history.replaceState(window.history.state, '', query); }