Ce tutoriel fait partie de la Construire votre démarrage avec la série PHP sur Envato Tuts +. Dans cette série, je vous guide dans le lancement d’une startup du concept à la réalité en utilisant mes Planificateur de réunion application comme exemple de la vie réelle. À chaque étape du processus, je publierai le code de Meeting Planner sous forme d’exemples open source à partir desquels vous pourrez apprendre. Je traiterai également les problèmes liés au démarrage au fur et à mesure qu'ils surviennent.
La planification de réunions avec plusieurs participants faisait toujours partie de mon plan, mais ne faisait pas partie du plus ancien produit Minimum Viable (MVP). La version alpha de Meeting Planner a été lancée avec une planification 1: 1 uniquement. L’objectif de soutenir l’horaire des groupes figurait sur la liste des tâches, comme le mont Everest, à un alpiniste visant les sept sommets (et je ne suis même pas un alpiniste en plein air)..
Les réunions à plusieurs participants sont les plus difficiles à planifier et sont donc précieuses pour le produit Meeting Planner. J'étais enthousiasmé lorsque la liste de tâches bêta a atteint le point où je pouvais commencer à travailler sur cette.
J'ai planifié, structuré et codé en gardant à l'esprit les réunions de groupe depuis le début. J'espérais que la mise à jour du site pour cette fonctionnalité ne nécessiterait pas de changements importants dans l'UX ou des mises à jour de codage. Il s'est avéré que cela nécessitait un chemin intermédiaire, 7 à 10 jours de travail et de tests très ciblés, mais aucune refonte majeure de l'architecture..
En fait, les tests se sont avérés être l’aspect le plus difficile de la création de cette fonctionnalité. Cela a également permis de révéler des lacunes dans le code précédent. C'est simplement que ce n'est pas facile… envoyer à plusieurs adresses électroniques, en vérifiant que chacune d'elles reçoit toutes les notifications appropriées, mais pas les mauvaises notifications, et voit toutes les options de menu correctes sur tout le site..
Dans le tutoriel d'aujourd'hui, je vais expliquer comment activer plusieurs participants, mettre à niveau l'UX pour les groupes, nommer des organisateurs, supprimer des participants et trier les options de date, heure et lieu en fonction de leur popularité auprès des participants..
Dans le prochain tutoriel, je décrirai le reste du travail: examiner toutes les zones du site affectées par plusieurs réunions de participants, gérer et afficher intelligemment des listes de destinataires de statut différent, gérer correctement les notifications et le filtrage des notifications pour les groupes, et enfin mise à niveau de la fonctionnalité de changements de réunion récemment lancée.
Veuillez planifier une réunion de groupe aujourd'hui! Partagez vos opinions et commentaires dans les commentaires ci-dessous.
Je participe aux discussions, mais vous pouvez également me joindre à @reifman sur Twitter. Je suis toujours ouvert aux nouvelles idées de fonctionnalités de Meeting Planner ainsi qu'aux suggestions pour les futurs épisodes de la série..
Pour rappel, tout le code de Meeting Planner est fourni en open source et écrit dans le framework Yii2 pour PHP. Si vous souhaitez en savoir plus sur Yii2, consultez mes séries parallèles Programming With Yii2. J'ai entendu beaucoup de choses sur Laravel, mais Yii2 répond toujours à mes besoins rapidement et facilement.
Lorsque j'ai conçu l'interface de planification de Meeting Planner pour la première fois, elle indiquait la disponibilité actuelle de l'autre participant dans sa propre colonne. Et c'était un peu déroutant car il y avait des contrôles désactivés.
À ce moment-là, je me demandais comment je ferais de la place pour afficher la disponibilité des groupes..
Heureusement, lorsque j'ai reconstruit l'UX pour une meilleure expérience de réaction, j'ai remplacé la colonne de disponibilité du participant par un court résumé de texte:
Le résumé textuel de la disponibilité conviendrait par hasard pour les réunions de groupe.
En repensant d'abord pour le mobile, j'ai résolu le problème le plus important lié à l'UX pour les réunions avec plusieurs participants.!
Commençons par parcourir tout le code et tester les nombreuses réunions de participants requises.
L'aspect le plus drôle des réunions de groupe est que leur activation était simple. Je devais juste désactiver la désactivation de la plus l'icône bouton sur le Qui panel pour les réunions en phase de planification:
= Html::a(Yii::t('frontend',"), ['/participant/create', 'meeting_id' => $ model-> id], ['class' => 'btn btn-primary'. ($ model-> status> = $ model :: STATUS_CONFIRMED? 'disabled': "). ' glyphicon glyphicon-plus '])?>
Ensuite, j'ai commencé par créer un MEETING_LIMIT
dans le modèle du participant:
la classe Participant s étend \ yii \ db \ ActiveRecord … const MEETING_LIMIT = 15;
Il est utilisé dans ParticipantController :: actionCreate ()
sur soumettre:
fonction publique actionCreate ($ meeting_id) if (! Participant :: insideLimit ($ meeting_id)) Yii :: $ app-> getSession () -> setFlash ('erreur', Yii :: t ('frontend', 'Désolé , vous avez atteint le nombre maximum de participants par réunion. Contactez le support technique si vous avez besoin d’aide supplémentaire ou si vous souhaitez faire part de vos commentaires. ')); return $ this-> redirect (['/ meeting / view', 'id' => $ meeting_id]);
Pendant longtemps, je voulais permettre aux organisateurs de réunions de supprimer des participants, des lieux et des dates sans surcharger l'interface utilisateur. De même, j'ai réalisé qu'il pouvait y avoir plusieurs commandes à exécuter sur les participants.
Après avoir trouvé une telle utilité dans le bouton déroulant Bootstrap compact du tutoriel Commandes avancées, j'ai décidé de l'utiliser pour afficher les participants à la réunion:
Les organisateurs sont désignés par une étoile. Les participants qui ont refusé la réunion sont affichés en orange. Les participants que les organisateurs suppriment sont affichés en rouge.
Voici le code dans mon nouveau /frontend/views/participant/_buttons.php partial:
- = Html::a(Yii::t('frontend','Send a message'),Url::to('mailto:'.$model->propriétaire-> email))?>
Tout le monde peut désormais envoyer un message à n’importe quel participant (les fonctions de notes de la réunion sont actuellement distribuées à tous les participants)..
Les organisateurs voient un menu déroulant plus profond qui leur permet d’oindre des organisateurs supplémentaires, c.-à-d.. Faire organisateur. C'est maintenant une fonctionnalité très cool. Les organisateurs recevront des notifications plus complètes et auront plus de pouvoir tout au long des phases de planification. Ils peuvent aussi Supprimer les participants.
J'ai décidé sur un coup de tête d'AJAXify toutes ces options de menu. Cela s’est avéré nécessiter plusieurs heures complexes de codage.
Voici le code qui définit le menu du bouton initial et prépare le JavaScript:
participants)> 0) foreach ($ modèle-> participants sous forme de $ p) if ($ p-> participant-> id == Yii :: $ app-> user-> getId ()) continue; $ btn_color = 'btn-default'; if ($ p-> status == Participant :: STATUS_DECLINED) $ btn_color = 'btn-warning'; else if ($ p-> statut == Participant :: STATUS_REMOVED || $ p-> statut == Participant :: STATUS_DECLINED_REMOVED) $ btn_color = 'btn-danger'; ?>
- = Html::a(Yii::t('frontend','Send a message'),Url::to('mailto:'.$p->participant-> email))?>
isOrganizer ()) ?>- ">= Html::a(Yii::t('frontend','Make organizer'),'javascript:void(0);',['onclick' => "toggleOrganizer ($ p-> id, true); retourne false;"]); ?>
- ">= Html::a(Yii::t('frontend','Revoke organizer role'),'javascript:void(0);',['onclick' => "toggleOrganizer ($ p-> id, false); retourne false;"]); ?>
- ">= Html::a(Yii::t('frontend','Remove participant'),'javascript:void(0);',['onclick' => "toggleParticipant ($ p-> id, false, $ p-> status); retourne false;"]); ?>
- ">= Html::a(Yii::t('frontend','Restore participant'),'javascript:void(0);',['onclick' => "toggleParticipant ($ p-> id, true, $ p-> status); retourne false;"]); ?>
Il y a tellement d'états de boutons, de couleurs et d'étoiles à mettre à jour lors de modifications interactives sur une page que le code devient assez complexe. J'ai ajouté des fonctions au fichier JavaScript meeting.js pour toggleOrganizer ()
, c.-à-d. créer / annuler un organisateur, et toggleParticipant ()
,c'est-à-dire supprimer / restaurer un participant en tant que participant.
fonction toggleOrganizer (id, val) if (val === true) arg2 = 1; else arg2 = 0; $ .ajax (url: $ ('# url_prefix'). val () + '/ participant / toggleorganizer', données: id: id, val: arg2, succès: fonction (données) if (données) if (val === false) $ ('# étoile _' + id) .addClass ("caché"); $ ('# ro _' + id) .addClass ("caché"); $ ('# mo_' + id) .removeClass ("caché"); else $ ('# star _' + id) .removeClass ("caché"); $ ('# ro _' + id) .removeClass ("caché"); $ ( '#mo _' + id) .addClass ("hidden"); return true;); fonction toggleParticipant (id, val, état_origine) if (val === true) arg2 = 1; else arg2 = 0; $ .ajax (url: $ ('# url_prefix'). val () + '/ participant / toggleparticipant', data: id: id, val: arg2, statut_original: statut_origine, succès: fonction (données) if (data) if (val === false) $ ('# rp _' + id) .addClass ("caché"); $ ('# rstp _' + id) .removeClass ("caché"); $ ( '#btn _' + id) .addClass ("btn-danger"); $ ('# btn _' + id) .removeClass ("btn-default"); else $ ('# rp _' + id) .removeClass ("hidden"); $ ('# rstp _' + id) .addClass ("hidden"); if (statut_origine == 100) $ ('# btn _' + id) .addClass ("btn-warning"); $ ('# btn _' + id) .removeClass ("btn-danger"); else $ ('# btn _' + id) .addClass ("btn-default"); $ ('# btn _' + id) .removeClass ("btn-danger"); return true;);
Ces méthodes de contrôleur JSON associées dans ParticipantController.php étaient nécessaires pour traiter les demandes de basculement et mettre à jour les bases de données:
fonction publique actionToggleorganizer ($ id, $ val) Yii :: $ app-> réponse-> format = \ yii \ web \ Response :: FORMAT_JSON; // change le paramètre $ p = Participant :: findOne ($ id); if ($ p-> réunion-> isOrganizer ()) $ p-> email = $ p-> participant-> email; if ($ val == 1) $ p-> participant_type = Participant :: TYPE_ORGANIZER; else $ p-> participant_type = Participant :: TYPE_DEFAULT; $ p-> update (); retourne vrai; else return false; fonction publique actionToggleparticipant ($ id, $ val) Yii :: $ app-> réponse-> format = \ yii \ web \ Response :: FORMAT_JSON; // change le paramètre $ p = Participant :: findOne ($ id); if ($ p-> réunion-> isOrganizer ()) $ p-> email = $ p-> participant-> email; if ($ val == 0) if ($ p-> status == Participant :: STATUS_DECLINED) $ p-> status = Participant :: STATUS_DECLINED_REMOVED; else $ p-> status = Participant :: STATUS_REMOVED; else if ($ p-> status == Participant :: STATUS_DECLINED_REMOVED) $ p-> status = Participant :: STATUS_DECLINED; else $ p-> status = Participant :: STATUS_DEFAULT; $ p-> update (); retourne vrai; else return false;
À ce moment-là, je réalisais également que plus le nombre de destinataires et d’options augmentant en complexité, plus le défilement serait complexe. J'ai décidé d'implémenter la fonctionnalité accordéon Bootstrap pour tous les panneaux de notre vue réunion.
En d'autres termes, vous pouvez maintenant cliquer sur un en-tête pour réduire ou ouvrir chaque panneau et / ou tous les panneaux..
Voici les modifications apportées aux partiels pour le lieu de réunion _panel.php:
= Yii::t('frontend','Where') ?>
compter<=1) ?> = Yii::t('frontend','add places for participants or switch to \'virtual\") ?> compter> 1) ?> = Yii::t('frontend','are listed places okay? ') ?> …switchVirtual == $ model :: SWITCH_VIRTUAL? 'none': 'block'); ?>compte> 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],])?>
Notez les paramètres ci-dessus sur le
rubrique panneau
et puis la div environnante pour le plus tardpanneau-corps
. Ceux-ci contrôlent l'ouverture et la réduction de chaque panneau.Cela a conduit à quelques petits problèmes esthétiques, tels que le rembourrage indésirable de la liste d'éléments, que je devrai nettoyer à l'avenir..
Infrastructure modèle pour les réunions de groupe
Bien que je planifie de nombreux participants depuis presque le début, des améliorations mineures à modestes ont été apportées à l'infrastructure pour les prendre en charge..
Tandis que le
MeetingTimeChoice
etMeetingPlaceChoice
Les modèles vérifient si les participants préfèrent des dates et des lieux spécifiques. Je souhaitais suivre la disponibilité globale de tous les participants à chaque date, heure et lieu. Cela me permettrait de trier les lieux et les heures en fonction de leur popularité et d'afficher les paramètres les plus populaires en haut des panneaux..Tout d'abord, j'ai créé une migration pour ajouter cela aux deux modèles. Il est rare qu'une migration de mine affecte plusieurs modèles, ce qui en fait un type de spécial:
db-> nomDuPort === 'mysql') $ tableOptions = 'CHARACTER 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', 'availability');Grâce à cette capacité, j'ai pu afficher les dates et lieux de réunion possibles, classés par ordre de popularité parmi les participants, de
MeetingController :: actionView ()
:$ timeProvider = new ActiveDataProvider (['query' => MeetingTime :: find () -> où (['meeting_id' => $ id]), 'sort' => ['defaultOrder' => ['availability' => SORT_DESC]],]); $ placeProvider = new ActiveDataProvider (['query' => MeetingPlace :: find () -> où (['meeting_id' => $ id]), 'sort' => ['defaultOrder' => ['availability' => SORT_DESC]],]);Vous pouvez le voir en action dans la capture d'écran de planification ci-dessous:
Pour savoir si les participants sont des organisateurs et permettre un futur retrait des notifications d'une réunion spécifique, j'ai ajouté cette migration pour la table des participants:
db-> nomDuPort === 'mysql') $ tableOptions = 'CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB'; $ this-> addColumn ('% participant', 'type_participant', Schema :: TYPE_SMALLINT. 'NOT NULL DEFAULT 0'); $ this-> addColumn ('% participant', 'notify', Schema :: TYPE_SMALLINT. 'NOT NULL DEFAULT 0'); public function down () $ this-> dropColumn ('% participant', 'type_participant'); $ this-> dropColumn ('% participant', 'notify');J'ai également ajouté un certain nombre de constantes dans Participant.php pour utiliser ces propriétés:
la classe Participant s étend \ 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;Et je savais qu'il serait utile d'avoir des fonctions d'assistance dans le modèle de réunion massif. Par exemple,
IsOrganizer ()
me dit si le spectateur actuel est un organisateur de réunion:fonction publique isOrganizer () $ user_id = Yii :: $ app-> user-> getId (); if ($ user_id == $ this-> owner_id) return true; else foreach ($ this-> participants en tant que $ p) if ($ user_id == $ p-> participant_id) if ($ p-> participant_type == Participant :: TYPE_ORGANIZER) return true; else return false; return false;Attendez, il y a plus?
Comme vous pouvez le constater, cette fonctionnalité nécessite beaucoup de travail. Dans le prochain épisode, je couvrirai la seconde moitié du développement et des tests requis pour lancer plusieurs réunions de participants: chaînes de destinataires, notifications, demandes et réponses aux demandes..
Si vous ne l'avez pas encore fait, organisez votre première réunion avec Meeting Planner et essayez tout cela. S'il vous plaît partager vos commentaires dans les commentaires ci-dessous.
Un tutoriel sur le financement participatif est également en préparation. Veuillez suivre notre page WeFunder Meeting Planner..
Vous pouvez également me contacter @reifman. Je suis toujours ouvert aux nouvelles idées de fonctionnalités et suggestions de sujets pour les prochains tutoriels.
Restez à l'affût de tout cela et de plusieurs autres tutoriels à venir en consultant la série Construire son démarrage avec PHP.
Liens connexes
- Planificateur de réunion
- Suivre le profil de financement de Meeting Planner
- Programmation avec la série Yii2 (Envato Tuts +)