From 4f25869a4cea796b2a14e3268669a4885b2907b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Walid=20Mujahid=20=D9=88=D9=84=D9=8A=D8=AF=20=D9=85=D8=AC?= =?UTF-8?q?=D8=A7=D9=87=D8=AF?= Date: Tue, 4 Aug 2020 03:36:14 -0400 Subject: [PATCH] Hackathons List Page (#6297) * add nav * finish new hackthon section;move subscription section * update hackathon card * add tribes section * add featured hackathon section in header * style: center text;change margins * style: remove gutter width;resize image * style: add image height;remove margins from featured image * add customisable width/height for featured logo * style: handle smaller screens * fix: recreate migrations * add no-featured-hackathon section * TODO: filtering tribes TODO: if no hackathon is ongoing, default to tribes who participated in the most number of hackathons. TODO: if no hackathon going, show tribes that most recently listed their bounties. * style: update margins * fix: stop changing featured bool on each save * style: fix tribes grid and columns add rows to help space elements out properly and fix grid sizes. * fix: duplicate listing of same tribe * handle showing tribes from most recent finsihed hackathon * feat: set a default tab on hackathons list if current hackathons exists, the tab is defaulted to current. if there are no current hackathons, the default tab is upcoming. otherwise, the default tab is finish. * refactor: make variables plural * show top four tribes if no current or upcoming hackathon exists * fix migrations * refactor: move repetitive code into `get_hackathon_events` * rename get_hackathon_events to get_hackathon_event * refactor tribes filtering * move functions to dashboard.utils `get_hackathon_event`, `get_tribe`, `tribe_fields`, and `hackathons_funded` * fix migrations * fix: missing import * fix: recreate migrations * Fix styles and index errors * Remove unused images and fix extension * feat: add workshops * fix: misspelled attribute * add speaker avatar;finish workshops section * fix: recreate migrations needed merges and create missing migrations for commit: c6510fd7e165d8fd8563650dd956a1428fcb51f3 * remove uneeded margin * update copy * fix: recreate migrations * fix: padding and copy position * fix: recreate migrations * fix:recreate migrations * add back prize amount and number of hackers * fix: recreate migrations * fix subscription sextion layout * fix hackathon section better adjust to changes introduced in: https://github.com/gitcoinco/web/pull/6722 https://github.com/gitcoinco/web/pull/6766 * fix: card-logo larger than card-header for some images * add back deleted curly * fix: skip overhead of dropdown of profile instances * adjust workshop layout - remove `workshop-cover` class -was made an ID in error - set a `width` for speaker avatar - set width for workshop title instead of using a column * remove cover_max_width from HackathonWorkshop model * recreate migrations * adjust layout for hackathon card prize amount and builders row * recreate migrations * receate migrations * recreate migrations * recreate migrations * recreate migrations * refactor: use bootstrap position-relative class * refactor: remove commented lines * recreate migrations * recreate mgrations * remove featured hackathon * remove workshops section * remove tribe sections and trbe util functions * updste header background, logo and details * remove value of prizes and number of builders from card * recreate migrations * use footer colour * update subscription section * update tab section add a third item to the tab tuple to act as title in views. previous version (title, count) new version (id, title, count) done so I do not have rework it too much. This way, the title can be variable and can be renamed fairly simply while the the id remains constant. * update form button padding * add hackathon summary to model and template * remove lines in pre_save signal pertaining to removal of featured hackathon from model * fix display of hackathon summary * decrease padding to keep buttons on same line * maek hackathon summary font smaller * set secondary buttons * add sponsors list to hackathon card * remove count from tabs * adjust tablist sizing on smaller screens * remove styles and refactor * increase width of cards, logo sizes, and handle sizes for smaller screens * update cards * add showcase button * recreate migrations * recreate migrations * remove unused files * style: revert to previous style * style: add line * style: use `let` * use zoek1's updates changes from PR https://github.com/gitcoinco/web/pull/7087 : https://github.com/gitcoinco/web/commit/07455463009ab9409b914d8a362f8030f10aef84#diff-704cfd344337eee34d60c4265c814b3f * recreate migrations Co-authored-by: Miguel Angel G --- app/assets/v2/css/home.css | 8 + .../images/hackathon/hackathon-subscribe.png | Bin 0 -> 4762 bytes app/assets/v2/js/pages/hackathon-list.js | 20 ++ app/dashboard/admin.py | 21 +- .../migrations/0135_auto_20200728_1656.py | 45 ++++ app/dashboard/models.py | 24 ++ .../dashboard/hackathon/hackathons.html | 235 +++++++++++------- app/dashboard/utils.py | 19 +- app/dashboard/views.py | 52 +++- .../shared/svg-embed/h35px_hackathons.svg | 2 +- 10 files changed, 313 insertions(+), 113 deletions(-) create mode 100644 app/assets/v2/images/hackathon/hackathon-subscribe.png create mode 100644 app/assets/v2/js/pages/hackathon-list.js create mode 100644 app/dashboard/migrations/0135_auto_20200728_1656.py diff --git a/app/assets/v2/css/home.css b/app/assets/v2/css/home.css index 24f9e91b5ce..f1f227811bb 100644 --- a/app/assets/v2/css/home.css +++ b/app/assets/v2/css/home.css @@ -510,6 +510,14 @@ figure:hover::before { .video-row { grid-template-columns: 1fr; } + + .box-cta { + margin: 0 !important; + } + + .work-internet { + width: 17rem; + } } @media (max-width: 768px) { diff --git a/app/assets/v2/images/hackathon/hackathon-subscribe.png b/app/assets/v2/images/hackathon/hackathon-subscribe.png new file mode 100644 index 0000000000000000000000000000000000000000..c9655ee3890d016681605a7110d4302c545e94e9 GIT binary patch literal 4762 zcmV;L5@qd)P)1^@s6HFoXR00009a7bBm000XU z000XU0RWnu7ytkO0drDELIAGL9O(c600d`2O+f$vv5yPb=)@x|{BF5^{71NeB=wA#y}QAaWnVctlur9Tf*1M%-guXFW%EWZan%W!0IH z)t`#&>SDMCS?&mOg)0F=E+B*ul63mMuXokfYZQ~1kPgOme)IDW{Y!UMy{h`^yT5t> zKjNm-@dC3@j(i88LB^Hax^^hL1kp2qtp+k|@oe zGc(rzePFTM2XvW z?Bw>AAL#ihjHMl3-zUq7;0=br0XkrP4#-b4@H9T)Ffi#Rnu8|Hn zKGZvcYZ@DOMZbO~cm8~Z*P~g(>oez(1IT`4QVV*1*|levuchEn4YFcH-Qhg8@f6$y z`lS=;lO9Y&Nc^wyBZud9_>!Q>LQYu#aQO*a{Fb$h-#g8IeA90`6Cj~+*RH6&V$%~; z#IlI-wfr#<1{`LICvPEQ<~G6zbEXMlp)94ibST^e;^u_0c$t~vh4rIzvy1+H)z2xH z*Gs>=?tN%(Z^HtHjdVcusI_`Su+NDKR>%_Nð~R;K6;sC3%xXpklWwjMvs)iyWz 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 literal 0 HcmV?d00001 diff --git a/app/assets/v2/js/pages/hackathon-list.js b/app/assets/v2/js/pages/hackathon-list.js new file mode 100644 index 00000000000..5580c46ba34 --- /dev/null +++ b/app/assets/v2/js/pages/hackathon-list.js @@ -0,0 +1,20 @@ +$(document).ready(function() { + $(document).on('click', '#tabs a', function(e) { + e.preventDefault(); + let target = $(this).data('href'); + + $('.hackathons-list').addClass('hidden'); + $('.nav-link').removeClass('active'); + $('.nav-link').css('font-weight', ''); + $(this).addClass('active'); + $(this).css('font-weight', '700'); + + + $('.hackathon-list').addClass('hidden'); + $('.hackathon-list.' + target).removeClass('hidden'); + + $('html,body').animate({ + scrollTop: '+=1px' + }); + }); +}); diff --git a/app/dashboard/admin.py b/app/dashboard/admin.py index dfcd2234316..82c2da4cd17 100644 --- a/app/dashboard/admin.py +++ b/app/dashboard/admin.py @@ -26,11 +26,14 @@ from adminsortable2.admin import SortableInlineAdminMixin from .models import ( - Activity, Answer, BlockedURLFilter, BlockedUser, Bounty, BountyEvent, BountyFulfillment, BountyInvites, - BountySyncRequest, CoinRedemption, CoinRedemptionRequest, Coupon, Earning, FeedbackEntry, FundRequest, - HackathonEvent, HackathonProject, HackathonRegistration, HackathonSponsor, Interest, Investigation, LabsResearch, - ObjectView, Option, Poll, PollMedia, PortfolioItem, Profile, ProfileVerification, ProfileView, Question, - SearchHistory, Sponsor, Tip, TipPayout, TokenApproval, TribeMember, TribesSubscription, UserAction, + Activity, Answer, BlockedURLFilter, BlockedUser, Bounty, BountyEvent, + BountyFulfillment, BountyInvites, BountySyncRequest, CoinRedemption, + CoinRedemptionRequest, Coupon, Earning, FeedbackEntry, FundRequest, + HackathonEvent, HackathonProject, HackathonRegistration, HackathonSponsor, + HackathonWorkshop, Interest, Investigation, LabsResearch, ObjectView, + Option, Poll, PollMedia, PortfolioItem, Profile, ProfileVerification, + ProfileView, Question, SearchHistory, Sponsor, Tip, TipPayout, + TokenApproval, TribeMember, TribesSubscription, UserAction, UserVerificationModel, ) @@ -367,6 +370,13 @@ class HackathonSponsorAdmin(admin.ModelAdmin): list_display = ['pk', 'hackathon', 'sponsor', 'sponsor_type'] +class HackathonWorkshopAdmin(admin.ModelAdmin): + """The admin object for the HackathonWorkshop model.""" + + raw_id_fields = ['speaker'] + list_display = ['pk', 'start_date', 'hackathon', 'speaker', 'url'] + + class SponsorAdmin(admin.ModelAdmin): """The admin object for the Sponsor model.""" @@ -589,6 +599,7 @@ class ProfileVerificationAdmin(admin.ModelAdmin): admin.site.register(Sponsor, SponsorAdmin) admin.site.register(HackathonEvent, HackathonEventAdmin) admin.site.register(HackathonSponsor, HackathonSponsorAdmin) +admin.site.register(HackathonWorkshop, HackathonWorkshopAdmin) admin.site.register(HackathonRegistration, HackathonRegistrationAdmin) admin.site.register(HackathonProject, HackathonProjectAdmin) admin.site.register(FeedbackEntry, FeedbackAdmin) diff --git a/app/dashboard/migrations/0135_auto_20200728_1656.py b/app/dashboard/migrations/0135_auto_20200728_1656.py new file mode 100644 index 00000000000..310c5cf4eb5 --- /dev/null +++ b/app/dashboard/migrations/0135_auto_20200728_1656.py @@ -0,0 +1,45 @@ +# Generated by Django 2.2.4 on 2020-07-28 16:56 + +import datetime +from django.db import migrations, models +import django.db.models.deletion +from django.utils.timezone import utc +import economy.models + + +class Migration(migrations.Migration): + + dependencies = [ + ('dashboard', '0134_auto_20200728_1114'), + ] + + operations = [ + migrations.AddField( + model_name='hackathonevent', + name='hackathon_summary', + field=models.CharField(blank=True, help_text='280 char summary that shows up on hackathon cards on the hackathon list page', max_length=280), + ), + migrations.AlterField( + model_name='tribessubscription', + name='expires_on', + field=models.DateTimeField(blank=True, default=datetime.datetime(2021, 7, 28, 16, 56, 46, 271248, tzinfo=utc), null=True), + ), + migrations.CreateModel( + name='HackathonWorkshop', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('created_on', models.DateTimeField(db_index=True, default=economy.models.get_time)), + ('modified_on', models.DateTimeField(default=economy.models.get_time)), + ('name', models.CharField(max_length=255)), + ('start_date', models.DateTimeField()), + ('cover', models.ImageField(upload_to='')), + ('url', models.URLField(help_text='Blog link, calendar link, or other.')), + ('visible', models.BooleanField(default=True, help_text='Can this HackathonWorkshop be seen on /hackathons ?')), + ('hackathon', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='workshop_event', to='dashboard.HackathonEvent')), + ('speaker', models.ForeignKey(help_text='Main speaker profile.', on_delete=django.db.models.deletion.CASCADE, related_name='workshop_speaker', to='dashboard.Profile')), + ], + options={ + 'abstract': False, + }, + ), + ] diff --git a/app/dashboard/models.py b/app/dashboard/models.py index 27cd59b786a..29262ecb539 100644 --- a/app/dashboard/models.py +++ b/app/dashboard/models.py @@ -4702,10 +4702,12 @@ class HackathonEvent(SuperModel): sponsors = models.ManyToManyField(Sponsor, through='HackathonSponsor') sponsor_profiles = models.ManyToManyField('dashboard.Profile', blank=True, limit_choices_to={'data__type': 'Organization'}) show_results = models.BooleanField(help_text=_('Hide/Show the links to access hackathon results'), default=True) + hackathon_summary = models.CharField(max_length=280, blank=True, help_text=_('280 char summary that shows up on hackathon cards on the hackathon list page')) description = models.TextField(default='', blank=True, help_text=_('HTML rich description.')) quest_link = models.CharField(max_length=255, blank=True) chat_channel_id = models.CharField(max_length=255, blank=True, null=True) visible = models.BooleanField(help_text=_('Can this HackathonEvent be seeing on /hackathons ?'), default=True) + default_channels = ArrayField(models.CharField(max_length=255), blank=True, default=list) objects = HackathonEventQuerySet.as_manager() display_showcase = models.BooleanField(default=False) @@ -4791,6 +4793,7 @@ def save(self, *args, **kwargs): self.slug = slugify(self.name) super().save(*args, **kwargs) + # method for updating @receiver(pre_save, sender=HackathonEvent, dispatch_uid="psave_hackathonevent") def psave_hackathonevent(sender, instance, **kwargs): @@ -4812,6 +4815,7 @@ def psave_hackathonevent(sender, instance, **kwargs): ) + class HackathonSponsor(SuperModel): SPONSOR_TYPES = [ ('G', 'Gold'), @@ -5429,3 +5433,23 @@ class ProfileVerification(SuperModel): def __str__(self): return f'{self.phone_number} ({self.caller_type}) from {self.country_code} request ${self.delivery_method} code at {self.created_on}' + + +class HackathonWorkshop(SuperModel): + name = models.CharField(max_length=255) + start_date = models.DateTimeField() + cover = models.ImageField() + hackathon = models.ForeignKey( + 'dashboard.HackathonEvent', + related_name='workshop_event', + on_delete=models.CASCADE, + blank=True, null=True + ) + speaker = models.ForeignKey( + 'dashboard.Profile', + related_name='workshop_speaker', + on_delete=models.CASCADE, + help_text='Main speaker profile.' + ) + url = models.URLField(help_text='Blog link, calendar link, or other.') + visible = models.BooleanField(help_text=_('Can this HackathonWorkshop be seen on /hackathons ?'), default=True) diff --git a/app/dashboard/templates/dashboard/hackathon/hackathons.html b/app/dashboard/templates/dashboard/hackathon/hackathons.html index 8be4af66a7f..09f8b537eee 100644 --- a/app/dashboard/templates/dashboard/hackathon/hackathons.html +++ b/app/dashboard/templates/dashboard/hackathon/hackathons.html @@ -22,19 +22,28 @@ {% include 'shared/head.html' %} {% include 'shared/cards.html' %} + -
- -
- -
- {% firstof hackathon.logo_svg or hackathon.logo as logo %} - {% if logo %} - - {% else %} - - {% endif %} -
- -
-
- - {{ hackathon.name }} - -
-
- From - - To - -
-
- {% if hackathon.end_date|timesince <= "1 min" %} - - - Join - - {% endif %} - {% if hackathon.start_date|timesince >= "1 min" %} - - - Prizes - - {% endif %} - {% if hackathon.show_results %} - - - Projects - - {% endif %} - {% if hackathon.display_showcase %} - - - Showcase - - {% endif %} -
-
+
+
+ +
+
+ +
+ {% if events|length %} +
+
+ {% for event in events %} + + +
+ +
+ +
+ {% firstof event.hackathon.logo_svg or event.hackathon.logo as logo %} + {% if logo %} + + {% else %} + + {% endif %} +
+ +
+
+ + {{ event.hackathon.name }} + +
+
+ From + + To + +
+
+

{{ event.hackathon.hackathon_summary }}

+
+
+ Sponsored by + {% for sponsor in event.hackathon.sponsors.all %} + + {% endfor %}
- {% endfor %} +
+ {% if event.hackathon.end_date|timesince <= "1 min" %} + + + Join + + {% endif %} + {% if event.hackathon.display_showcase %} + + + + Showcase + + {% endif %} + {% if event.hackathon.start_date|timesince >= "1 min" and event.hackathon.end_date|timesince <= "1 min"%} + + + Prizes + + {% endif %} + {% if event.hackathon.show_results %} + + + Projects + + {% endif %} +
+
+
-
+ {% endfor %} +
+
{% endif %} - {% endfor %} +
+ +
{% include 'shared/analytics.html' %} {% include 'shared/footer_scripts.html' %} {% include 'shared/footer.html' %} + {% block 'scripts' %} + + {% endblock %} diff --git a/app/dashboard/utils.py b/app/dashboard/utils.py index 3ddc8d92e65..73154dea992 100644 --- a/app/dashboard/utils.py +++ b/app/dashboard/utils.py @@ -34,7 +34,7 @@ from compliance.models import Country, Entity from cytoolz import compose from dashboard.helpers import UnsupportedSchemaException, normalize_url, process_bounty_changes, process_bounty_details -from dashboard.models import Activity, BlockedUser, Bounty, BountyFulfillment, Profile, UserAction +from dashboard.models import Activity, BlockedUser, Bounty, BountyFulfillment, Profile, UserAction, HackathonRegistration from dashboard.sync.celo import sync_celo_payout from dashboard.sync.etc import sync_etc_payout from dashboard.sync.eth import sync_eth_payout @@ -1017,7 +1017,7 @@ def get_url_first_indexes(): return ['_administration','about','action','actions','activity','api','avatar','blog','bounties','bounty','btctalk','casestudies','casestudy','chat','community','contributor','contributor_dashboard','credit','dashboard','docs','dynamic','explorer','extension','faucet','fb','feedback','funder','funder_dashboard','funding','gas','ghlogin','github','gitter','grant','grants','hackathon','hackathonlist','hackathons','health','help','home','how','impersonate','inbox','interest','issue','itunes','jobs','jsi18n','kudos','l','labs','landing','lazy_load_kudos','lbcheck','leaderboard','legacy','legal','livestream','login','logout','mailing_list','medium','mission','modal','new','not_a_token','o','onboard','podcast','postcomment','press','presskit','products','profile','quests','reddit','refer','register_hackathon','requestincrease','requestmoney','requests','results','revenue','robotstxt','schwag','send','service','settings','sg_sendgrid_event_processor','sitemapsectionxml','sitemapxml','slack','spec','strbounty_network','submittoken','sync','terms','tip','townsquare','tribe','tribes','twitter','users','verified','vision','wallpaper','wallpapers','web3','whitepaper','wiki','wikiazAZ09azdAZdazd','youtube'] # TODO: figure out the recursion issue with the URLs at a later date # or just cache them in the backend dynamically - + urls = [] for p in get_all_urls(): url = p[0].split('/')[0] @@ -1087,3 +1087,18 @@ def get_token_recipient_senders(network, recipient_address, token_address): ) return [process_log(log) for log in logs] + + +def get_hackathon_event(title, event, network): + event_bounties = Bounty.objects.filter(event=event, network=network) + + return { + 'title': title, + 'hackathon': event, + 'value_in_usdt': sum( + prize_usdt.value_in_usdt_now + for prize_usdt + in event_bounties + ), + 'registrants': HackathonRegistration.objects.filter(hackathon=event).count() + } diff --git a/app/dashboard/views.py b/app/dashboard/views.py index 2cec25ead33..d9e8d537745 100644 --- a/app/dashboard/views.py +++ b/app/dashboard/views.py @@ -108,7 +108,7 @@ from .models import ( Activity, Answer, BlockedURLFilter, Bounty, BountyEvent, BountyFulfillment, BountyInvites, CoinRedemption, CoinRedemptionRequest, Coupon, Earning, FeedbackEntry, HackathonEvent, HackathonProject, HackathonRegistration, - HackathonSponsor, Interest, LabsResearch, Option, Poll, PortfolioItem, Profile, ProfileSerializer, + HackathonSponsor, HackathonWorkshop, Interest, LabsResearch, Option, Poll, PortfolioItem, Profile, ProfileSerializer, ProfileVerification, ProfileView, Question, SearchHistory, Sponsor, Subscription, Tool, ToolVote, TribeMember, UserAction, UserVerificationModel, ) @@ -120,7 +120,7 @@ from .utils import ( apply_new_bounty_deadline, get_bounty, get_bounty_id, get_context, get_custom_avatars, get_unrated_bounties_count, get_web3, has_tx_mined, is_valid_eth_address, re_market_bounty, record_user_action_on_interest, - release_bounty_to_the_public, sync_payout, web3_process_bounty, + release_bounty_to_the_public, sync_payout, web3_process_bounty, get_hackathon_event, ) logger = logging.getLogger(__name__) @@ -4304,23 +4304,53 @@ def hackathon_registration(request): def get_hackathons(request): """Handle rendering all Hackathons.""" - events = { - 'current': HackathonEvent.objects.current().filter(visible=True).order_by('start_date'), - 'upcoming': HackathonEvent.objects.upcoming().filter(visible=True).order_by('start_date'), - 'finished': HackathonEvent.objects.finished().filter(visible=True).order_by('-start_date'), - } + current_hackathon_events = HackathonEvent.objects.current().filter(visible=True).order_by('-start_date') + upcoming_hackathon_events = HackathonEvent.objects.upcoming().filter(visible=True).order_by('-start_date') + finished_hackathon_events = HackathonEvent.objects.finished().filter(visible=True).order_by('-start_date') + all_hackathon_events = HackathonEvent.objects.all().filter(visible=True) + + network = get_default_network() + + tabs = [ + ('current', 'happening now'), + ('upcoming', 'upcoming'), + ('finished', 'completed'), + ] + + hackathon_events = [] + + if current_hackathon_events.exists(): + for event in current_hackathon_events: + event_dict = get_hackathon_event('current', event, network) + hackathon_events.append(event_dict) + + if upcoming_hackathon_events.exists(): + for event in upcoming_hackathon_events: + event_dict = get_hackathon_event('upcoming', event, network) + hackathon_events.append(event_dict) + + if finished_hackathon_events.exists(): + for event in finished_hackathon_events: + event_dict = get_hackathon_event('finished', event, network) + hackathon_events.append(event_dict) - pks = HackathonEvent.objects.filter(visible=True).values_list('pk', flat=True) - if len(pks): - increment_view_count.delay(list(pks), 'hackathon event', request.user.id, 'index') params = { 'active': 'hackathons', 'title': 'Hackathons', 'avatar_url': request.build_absolute_uri(static('v2/images/twitter_cards/tw_cards-02.png')), 'card_desc': "Gitcoin runs Virtual Hackathons. Learn, earn, and connect with the best hackers in the space -- only on Gitcoin.", - 'events': events, + 'tabs': tabs, + 'events': hackathon_events, } + + if current_hackathon_events.exists(): + params['default_tab'] = 'current' + elif upcoming_hackathon_events.exists(): + params['default_tab'] = 'upcoming' + else: + params['default_tab'] = 'finished' + return TemplateResponse(request, 'dashboard/hackathon/hackathons.html', params) diff --git a/app/retail/templates/shared/svg-embed/h35px_hackathons.svg b/app/retail/templates/shared/svg-embed/h35px_hackathons.svg index 6112517a78c..ef25008df3e 100644 --- a/app/retail/templates/shared/svg-embed/h35px_hackathons.svg +++ b/app/retail/templates/shared/svg-embed/h35px_hackathons.svg @@ -1,2 +1,2 @@ -