Deze zelfstudie maakt deel uit van de Bouw je Startup met PHP-serie op Envato Tuts +. In deze serie begeleid ik je door het opstarten van een startup van concept naar realiteit met behulp van mijn Meeting Planner app als een realistisch voorbeeld. Elke stap die ik doe, zal ik de Meeting Planner-code vrijgeven als open-source voorbeelden waar je van kunt leren. Ik zal ook opstartgerelateerde zakelijke problemen aanpakken zodra deze zich voordoen.
Het plannen van vergaderingen met meerdere deelnemers was altijd onderdeel van mijn plan, maar maakte geen deel uit van het vroegste Minimum Viable Product (MVP). De alpha-release van Meeting Planner werd gelanceerd met slechts 1: 1 planning. Het doel om groepsplanning te ondersteunen zat op de takenlijst zoals de Mount Everest voor een klimmer gericht op de zeven toppen (en ik ben niet eens een buitenklimmer).
Meerdere deelnemersbijeenkomsten zijn het meest uitdagend om te plannen en daarom waardevol om het Meeting Planner-product te bieden. Ik was opgewonden toen de beta-takenlijst het punt bereikte dat ik hieraan kon beginnen.
Ik heb vanaf het begin al plannen, ontwerpen en coderen met groepsvergaderingen in gedachten. Ik hoopte dat het bijwerken van de site voor deze functie geen significante UX-wijzigingen of coderingsupdates zou vereisen. Het bleek een middenweg te vereisen, 7-10 dagen van zeer gericht werk en testen, maar geen grote re-architecting.
Testen bleek het moeilijkste aspect van het bouwen van deze functie te zijn. Het hielp ook om tekortkomingen in eerdere code te onthullen. Het is gewoon dat het niet gemakkelijk is ... naar meerdere e-mailadressen te verzenden, waarbij gecontroleerd wordt of elk van hen alle juiste meldingen ontvangt, maar niet de verkeerde meldingen - en alle juiste menu-opties door de hele site heen ziet.
In de tutorial van vandaag ga ik over het inschakelen van meerdere deelnemers, het upgraden van de UX voor groepen, het benoemen van organisatoren, het verwijderen van deelnemers en het sorteren van datum-, tijd- en plaatsopties op basis van hun populariteit bij deelnemers.
In de volgende zelfstudie zal ik de rest van het werk beschrijven: alle delen van de site bekijken die zijn beïnvloed door vergaderingen met meerdere deelnemers, die slim omgaan met lijsten met ontvangers met verschillende status, correct beheer van meldingen en meldingsfiltering voor groepen, en ten slotte het upgraden van de recent gestarte wijzigingsfunctie voor wijzigingsverzoeken.
Plan alsjeblieft een groepsbijeenkomst vandaag! Deel uw mening en feedback in de opmerkingen hieronder.
Ik neem deel aan de discussies, maar je kunt me ook bereiken @reifman op Twitter. Ik sta altijd open voor nieuwe functie-ideeën voor Meeting Planner en suggesties voor toekomstige serie-afleveringen.
Ter herinnering, alle code voor Meeting Planner wordt open source gegeven en geschreven in het Yii2 Framework voor PHP. Als je meer wilt weten over Yii2, bekijk dan mijn parallelle serie Programming With Yii2. Ik heb geweldige dingen over Laravel gehoord, maar Yii2 voldoet altijd snel en gemakkelijk aan mijn behoeften.
Toen ik de planningsinterface Meeting Planner voor het eerst ontwierp, toonde het de huidige beschikbaarheid van de andere deelnemer in zijn eigen kolom. En het was een beetje verwarrend omdat er bedieningen met een handicap waren.
Op dat moment maakte ik me zorgen over hoe ik ruimte zou maken voor het weergeven van de beschikbaarheid van groepen.
Gelukkig, toen ik de UX herbouwde voor een beter reagerende ervaring, heb ik de deelnemersbeschikbaarheidskolom vervangen door een kleine samenvatting:
Het summiere overzicht van de beschikbaarheid zou toevallig goed werken voor groepsbijeenkomsten.
Door eerst voor mobiel te herontwerpen, loste ik de belangrijkste UX-barrière op voor vergaderingen met meerdere deelnemers!
Laten we beginnen met het doorlopen van alle code en het testen van de vereiste vergaderingen voor meerdere deelnemers.
Het grappigste aspect van groepsbijeenkomsten is dat het activeren ervan eenvoudig was. Ik hoef alleen het uitschakelen van de. Uit te schakelen plus pictogram knop op de Wie paneel voor vergaderingen in de planningsfase:
= Html::a(Yii::t('frontend',"), ['/participant/create', 'meeting_id' => $ model-> id], ['class' => 'btn btn-primary'. ($ model-> status> = $ model :: STATUS_CONFIRMED? 'disabled': "). ' glyphicon glyphicon-plus '])?>
Toen begon ik met het maken van een MEETING_LIMIT
in het Deelnemersmodel:
klasse Deelnemer breidt \ yii \ db \ ActiveRecord ... const MEETING_LIMIT = 15;
Het is gebruikt in ParticipantController :: actionCreate ()
op verzenden:
public function actionCreate ($ meeting_id) if (! Participant :: withinLimit ($ meeting_id)) Yii :: $ app-> getSession () -> setFlash ('error', Yii :: t ('frontend', 'Sorry , je hebt het maximale aantal deelnemers per vergadering bereikt Neem contact op met ondersteuning als je extra hulp nodig hebt of feedback wilt geven. ')); return $ this-> redirect (['/ meeting / view', 'id' => $ meeting_id]);
Lange tijd wilde ik organisatoren van vergaderingen toestaan om deelnemers, plaatsen en dateertijden te verwijderen zonder de gebruikersinterface te overbelasten. Op dezelfde manier besefte ik dat er verschillende opdrachten kunnen zijn om op deelnemers uit te voeren.
Na het vinden van zoveel bruikbaarheid in de compacte vervolgkeuzeknop Bootstrap in de tutorial Advanced Commands, heb ik besloten om het te gebruiken voor het weergeven van deelnemers aan de vergadering:
Organisatoren worden aangeduid met een ster. Deelnemers die de vergadering hebben geweigerd, worden oranje weergegeven. Deelnemers die door organisatoren worden verwijderd, worden in rood weergegeven.
Hier is de code in mijn nieuwe partial /frontend/views/participant/_buttons.php:
- = Html::a(Yii::t('frontend','Send a message'),Url::to('mailto:'.$model->eigenaar-> e))?>
Iedereen kan nu een bericht naar elke deelnemer sturen (de functies voor vergadernotities worden momenteel verspreid onder alle deelnemers aan de vergadering).
Organisatoren zien een diepere dropdown waarmee ze extra organisatoren kunnen insmeren, d.w.z.. Maak organisator. Dit is nu een erg leuke functie. Organisatoren ontvangen meer complete meldingen en hebben meer macht tijdens de planningsfasen. Ze kunnen ook Verwijder deelnemers.
Ik besloot in een opwelling om al deze menu-opties te AJAXify. Dat bleek verschillende complexe codeeruren te vergen.
Hier is de code die het eerste knopmenu definieert en de JavaScript voorbereidt:
deelnemers)> 0) foreach ($ model-> deelnemers als $ p) if ($ p-> deelnemer-> id == Yii :: $ app-> gebruiker-> getId ()) doorgaan; $ btn_color = 'btn-default'; if ($ p-> status == Deelnemer :: STATUS_DECLINED) $ btn_color = 'btn-warning'; else if ($ p-> status == Deelnemer: STATUS_REMOVED || $ p-> status == Deelnemer :: STATUS_DECLINED_REMOVED) $ btn_color = 'btn-danger'; ?>
- = Html::a(Yii::t('frontend','Send a message'),Url::to('mailto:'.$p->participant-> e))?>
isOrganizer ()) ?>- ">= Html::a(Yii::t('frontend','Make organizer'),'javascript:void(0);',['onclick' => "toggleOrganizer ($ p-> id, true); return false;"]); ?>
- ">= Html::a(Yii::t('frontend','Revoke organizer role'),'javascript:void(0);',['onclick' => "toggleOrganizer ($ p-> id, false); return false;"]); ?>
- ">= Html::a(Yii::t('frontend','Remove participant'),'javascript:void(0);',['onclick' => "toggleParticipant ($ p-> id, false, $ p-> status); return false;"]); ?>
- ">= Html::a(Yii::t('frontend','Restore participant'),'javascript:void(0);',['onclick' => "toggleParticipant ($ p-> id, true, $ p-> status); return false;"]); ?>
Er zijn zoveel knopstatussen, kleuren en sterren die moeten worden bijgewerkt als er interactief op een pagina wijzigingen worden aangebracht waardoor de code behoorlijk ingewikkeld wordt. Ik heb functies toegevoegd aan het JavaScript-bestand meeting.js voor toggleOrganizer ()
, d.w.z. organiser maken / deactiveren, en toggleParticipant ()
,d.w.z. verwijder / herstel de deelnemer als deelnemer.
function toggleOrganizer (id, val) if (val === true) arg2 = 1; else arg2 = 0; $ .ajax (url: $ ('# url_prefix'). val () + '/ deelnemer / toggleorganizer', data: id: id, val: arg2, success: function (data) if (data) if (val === false) $ ('# star _' + id) .addClass ("hidden"); $ ('# ro _' + id) .addClass ("hidden"); $ ('# mo_' + id) .removeClass ("hidden"); else $ ('# star _' + id) .removeClass ("hidden"); $ ('# ro _' + id) .removeClass ("hidden"); $ ( '#mo _' + id) .addClass ("hidden"); return true;); function toggleParticipant (id, val, original_status) if (val === true) arg2 = 1; else arg2 = 0; $ .ajax (url: $ ('# url_prefix'). val () + '/ deelnemer / toggleparticipant', data: id: id, val: arg2, original_status: original_status, success: function (data) if (data) if (val === false) $ ('# rp _' + id) .addClass ("hidden"); $ ('# rstp _' + id) .removeClass ("hidden"); $ ( '#btn _' + id) .addClass ("btn-danger"); $ ('# btn _' + id) .removeClass ("btn-default"); else $ ('# rp _' + id) .removeClass ("verborgen"); $ ('# rstp _' + id) .addClass ("hidden"); if (original_status == 100) $ ('# btn _' + id) .addClass ("btn-warning"); $ ('# btn _' + id) .removeClass ("btn-danger"); else $ ('# btn _' + id) .addClass ("btn-default"); $ ('# btn _' + id) .removeClass ("btn-danger"); return true;);
Deze vereiste begeleidende JSON-controllermethoden in ParticipantController.php om de toggle-aanvragen te verwerken en de databases bij te werken:
public function actionToggleorganizer ($ id, $ val) Yii :: $ app-> response-> format = \ yii \ web \ Response :: FORMAT_JSON; // wijzig instelling $ p = Deelnemer :: findOne ($ id); if ($ p-> meeting-> isOrganizer ()) $ p-> email = $ p-> deelnemer-> email; if ($ val == 1) $ p-> participant_type = Deelnemer: TYPE_ORGANIZER; else $ p-> participant_type = Deelnemer :: TYPE_DEFAULT; $ p-> update (); geef waar terug; else return false; openbare functie actionToggleparticipant ($ id, $ val) Yii :: $ app-> response-> format = \ yii \ web \ Response :: FORMAT_JSON; // wijzig instelling $ p = Deelnemer :: findOne ($ id); if ($ p-> meeting-> isOrganizer ()) $ p-> email = $ p-> deelnemer-> email; if ($ val == 0) if ($ p-> status == Deelnemer :: STATUS_DECLINED) $ p-> status = Deelnemer: STATUS_DECLINED_REMOVED; else $ p-> status = Deelnemer: STATUS_REMOVED; else if ($ p-> status == Deelnemer :: STATUS_DECLINED_REMOVED) $ p-> status = Deelnemer: STATUS_DECLINED; else $ p-> status = Deelnemer: STATUS_DEFAULT; $ p-> update (); geef waar terug; else return false;
Op dit moment besefte ik ook dat naarmate vergaderingsplannen in complexiteit toenemen met meer ontvangers en opties, er meer scrollen zou zijn. Ik besloot om de Bootstrap-accordeonfunctie voor alle panelen in onze vergaderingsweergave te implementeren.
Met andere woorden, u kunt nu klikken op een titel om in te klappen of om elk en / of alle panelen te openen.
Dit zijn de wijzigingen in de partials voor ontmoetingsplaats _panel.php:
= Yii::t('frontend','Where') ?>
tellen<=1) ?> = Yii::t('frontend','add places for participants or switch to \'virtual\") ?> tel> 1) ?> = Yii::t('frontend','are listed places okay? ') ?> ...switchVirtual == $ model :: SWITCH_VIRTUAL 'none': 'block'); ?>tel> 0):?>= ListView::widget([ 'dataProvider' => $ placeProvider, 'itemOptions' => ['class' => 'item'], 'layout' => 'items', 'itemView' => '_list', 'viewParams' => ['placeCount' => $ placeProvider-> count, 'isOwner' => $ isOwner, 'participant_choose_place' => $ model-> meetingSettings ['participant_choose_place'], 'whereStatus' => $ whereStatus],])?>
Let op de bovenstaande instellingen op de
panel-titel
en dan de omringende div voor de laterepaneelvormig body
. Deze regelen de opening en inklappen van elk paneel.Dit leidde tot enkele kleine cosmetische problemen, zoals ongewenst opvullen rond de lijst met items, die ik in de toekomst moet opschonen.
Modelinfrastructuur voor groepsbijeenkomsten
Hoewel ik vanaf het begin voor meerdere deelnemers had gepland, waren er enkele kleine tot bescheiden infrastructuurverbeteringen om ze te ondersteunen.
Terwijl de
MeetingTimeChoice
enMeetingPlaceChoice
modellen houden bij of deelnemers de voorkeur geven aan specifieke dateertijden en -plaatsen, ik wilde de algemene beschikbaarheid voor alle deelnemers bijhouden op elke datum en tijd. Hiermee kan ik plaatsen en tijden sorteren op hoe populair ze zijn en de populairste instellingen bovenaan de panelen weergeven.Eerst heb ik een migratie gemaakt om dit aan beide modellen toe te voegen. Het komt zelden voor dat een migratie van mij meerdere modellen beïnvloedt, wat dit een speciaal soort maakt:
db-> driverName === 'mysql') $ tableOptions = 'KARAKTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB'; $ this-> addColumn ('% meeting_time', 'availability', Schema :: TYPE_SMALLINT. 'NOT NULL DEFAULT 0'); $ this-> addColumn ('% meeting_place', 'availability', Schema :: TYPE_SMALLINT. 'NOT NULL DEFAULT 0'); public function down () $ this-> dropColumn ('% meeting_time', 'availability'); $ This-> dropColumn ( '% meeting_place', 'beschikbaarheid');Met deze capaciteit kon ik beginnen met het weergeven van mogelijke datum en tijden van vergaderingen gesorteerd naar populariteit bij deelnemers, van
MeetingController :: actionView ()
:$ timeProvider = new ActiveDataProvider (['query' => MeetingTime :: find () -> where (['meeting_id' => $ id]), 'sort' => ['defaultOrder' => ['availability' => SORT_DESC]],]); $ placeProvider = new ActiveDataProvider (['query' => MeetingPlace :: find () -> where (['meeting_id' => $ id]), 'sort' => ['defaultOrder' => ['availability' => SORT_DESC]],]);U kunt dit in actie zien in het onderstaande planningsscherm:
Om te volgen of deelnemers organisatoren zijn en om in de toekomst af te zien van de meldingen van een specifieke vergadering, heb ik deze migratie toegevoegd aan de tabel Deelnemer:
db-> driverName === 'mysql') $ tableOptions = 'KARAKTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB'; $ this-> addColumn ('% participant', deelnemer_type ', Schema :: TYPE_SMALLINT.' NOT NULL DEFAULT 0 '); $ this-> addColumn ('% participant', 'notify', Schema :: TYPE_SMALLINT. 'NOT NULL DEFAULT 0'); public function down () $ this-> dropColumn ('% participant', 'deelnemer_type'); $ This-> dropColumn ( '% deelnemer', 'melden');Ik heb ook een aantal constanten toegevoegd aan Participant.php om met deze eigenschappen te werken:
klasse Deelnemer breidt \ yii \ db \ ActiveRecord const TYPE_DEFAULT = 0; const TYPE_ORGANIZER = 10; const NOTIFY_ON = 0; const NOTIFY_OFF = 1; const STATUS_DEFAULT = 0; const STATUS_REMOVED = 90; const STATUS_DECLINED = 100; const STATUS_DECLINED_REMOVED = 110;En ik wist dat het nuttig zou zijn om een aantal helperfuncties te hebben in het enorme vergadermodel. Bijvoorbeeld,
IsOrganizer ()
vertelt me of de huidige kijker een vergaderingorganisator is:public function isOrganizer () $ user_id = Yii :: $ app-> user-> getId (); if ($ user_id == $ this-> owner_id) return true; else foreach ($ this-> deelnemers als $ p) if ($ user_id == $ p-> deelnemer_id) if ($ p-> participant_type == Deelnemer :: TYPE_ORGANIZER) return true; else return false; return false;Wacht, er is meer?
Zoals je kunt zien, is er veel grond om deze functie te bouwen. In de volgende aflevering behandel ik de tweede helft van de ontwikkeling en tests die nodig zijn om vergaderingen met meerdere deelnemers te starten: ontvangstrings, meldingen, verzoeken en reageren op verzoeken.
Als u dat nog niet hebt gedaan, gaat u uw eerste vergadering plannen met Meeting Planner en probeert u dit allemaal. Deel uw feedback in de reacties hieronder.
Een tutorial over crowdfunding is ook in de maak, dus volg onze WeFunder Meeting Planner-pagina.
Je kunt me ook bereiken via @reifman. Ik sta altijd open voor nieuwe functie-ideeën en suggesties voor onderwerpen voor toekomstige zelfstudies.
Blijf op de hoogte van dit alles en meer komende tutorials door te kijken naar de Building Your Startup With PHP-serie.
Gerelateerde Links
- Meeting Planner
- Volg het financieringsprofiel van Meeting Planner
- Programmeren met de Yii2-serie (Envato Tuts +)