Статьи

Создание стартапа: настройка вида собрания

Конечный продукт
Что вы будете создавать

Это руководство является частью серии « Создай свой стартап с помощью PHP» на Envato Tuts +. В этой серии я проведу вас через запуск стартапа от концепции до реальности, используя мое приложение Meeting Planner в качестве примера из реальной жизни. На каждом этапе я буду публиковать код Планировщика собраний в качестве примеров с открытым исходным кодом, из которых вы можете извлечь уроки. Я также буду решать вопросы, связанные с бизнесом по мере их возникновения

Вы можете заметить, что между последним эпизодом и этим эпизодом был огромный разрыв во времени. В апреле 2015 года у меня была диагностирована опухоль головного мозга, которая потребовала хирургического вмешательства и облучения . В целом мне невероятно повезло, что я получил такую ​​хорошую помощь, и все прошло довольно хорошо — многие люди не имеют доступа к качественным ресурсам нейрохирургии, которые мне доступны благодаря медицинской страховке на Тихоокеанском северо-западе. С осени прошлого года я снова пишу для Envato Tuts + , но интересно наконец-то вернуть фокус стартапу, и я надеюсь, вам понравится.

В этом руководстве мы расскажем о пользовательских функциях, которые необходимы для предоставления различных представлений в зависимости от того, кто просматривает приглашения на собрания. Прежде чем мы начнем рассылать приглашения участникам по электронной почте, нам необходимо подготовить представление с потенциально ограниченными функциями, чтобы поделиться с ними. По сути, мы следим за тем, чтобы представление собрания было именно тем, что необходимо для владельца собрания и участника собрания. Следуйте, чтобы узнать, что нужно.

Весь код для Meeting Planner написан на Yii2 Framework для PHP, который имеет встроенную поддержку I18n. Если вы хотите узнать больше о Yii2, ознакомьтесь с нашей параллельной серией Программирование с Yii2 на Envato Tuts +.

Интересно, что потенциальный инвестор-ангел недавно обратился ко мне с просьбой предоставить ресурсы для ускорения процесса разработки нашего сайта — он видит ценность в концепции. Когда я выберу подходящий путь, чтобы продолжить, я буду держать вас в курсе. Во всяком случае, я надеюсь, что это создает интригующие новые учебные темы по управлению инвестиционным процессом в качестве предпринимателя.

Просто напоминание, я участвую в комментариях ниже. Мне особенно интересно, если у вас есть другие подходы, дополнительные идеи или вы хотите предложить темы для будущих уроков. Вы также можете связаться со мной в Twitter @reifman .

Это довольно увлекательно — в ближайшее время Meeting Planner будет рассылать приглашения приглашенным участникам. Однако для поддержки этого нам необходимо убедиться, что страница просмотра собрания настроена правильно. Если вы создали собрание, у вас есть определенные полномочия, такие как приглашение участников, добавление предлагаемых мест встречи, дат и времени, а также выбор окончательного выбора. В некоторых случаях организатор может предложить некоторые или все эти полномочия участникам.

По сути, мы должны уведомить приложение о том, кто просматривает страницу собрания, а затем настроить внешний вид и доступные команды. Yii делает большую часть этого довольно простым, но в нем много деталей.

Краткая оговорка об опыте пользователя

И позвольте мне сразу сказать, что на пути к минимально жизнеспособному продукту (MVP) потребуется много времени для доработки и доработки пользовательского опыта. Большая часть того, что я сейчас создаю, — это основная функциональность, позволяющая запустить альфа-версию для реального использования. Я знаю, что это выглядит грубым в некоторых местах и ​​не всегда будет казаться таким интуитивным, как вы хотите. Есть также недостатки кодирования, которые необходимо будет оптимизировать в будущем. Пожалуйста, не стесняйтесь оставлять свои мысли и комментарии ниже, и я буду принимать их во внимание для дальнейшей работы.

Вот взгляд на существующее представление собрания, которое видит создатель (или владелец):

Настройка вида собрания - вид собрания существующих кодов

Кнопка « Отправить» отправляет участнику приглашение по электронной почте с текущими открытыми параметрами, чтобы он мог оставить отзыв. Чекбоксы под Вами и Им позволяют зрителю выражать, работают ли для них место (а) и время (и). Флажки Выбрать позволяют зрителю определить конечное место и окончательное время. Кнопка « Завершить» помещает встречу в расписание с выбранными параметрами места и времени.

Конечно, по мере развития продукта мы хотим улучшить взаимодействие с пользователем несколькими способами и значительно его улучшить, но вот несколько функциональных элементов, которые мы хотели бы изменить для участников:

  • Кнопка Отправить не понадобится после того, как владелец доставит приглашение.
  • Участникам может быть разрешено или не разрешено финализировать варианты встреч.
  • Участники не смогут редактировать (значок карандаша) подробный текст встречи.
  • Участники не смогут добавлять людей в это время (для нашего MVP).
  • Участники могут или не могут добавлять места (значок плюс).
  • Участники могут или не могут добавлять даты и время (значок плюс).
  • На панелях « Места» и « Даты и время» мы хотим показать выбор текущего зрителя в разделе столбец You и данные другого лица в них .
  • На панелях « Места» и « Даты и время» участники могут или не могут выбрать окончательный вариант. место и время.

Все эти варианты должны быть рассмотрены в нашей работе сегодня. Давайте пройдемся по тому, что требуется для создания этих функций.

Если вы следуете вместе с кодом, описанные здесь обновления включены в этот выпуск на GitHub .

Yii Framework предоставляет текущий user_id для зрителя здесь:

1
$user_id = Yii::$app->user->getId()

Модель Meeting имеет свойство $owner_id и функцию isOwner чтобы помочь определить, является ли текущий зритель создателем собрания. Если нет, зритель будет иметь меньше контроля над собранием.

Я создал несколько вспомогательных функций в модели Meeting, чтобы сделать это быстрее:

1
2
3
4
5
6
7
8
public function setViewer() {
     $this->viewer_id = Yii::$app->user->getId();
     if ($this->owner_id == $this->viewer_id) {
       $this->viewer = Meeting::VIEWER_ORGANIZER;
     } else {
       $this->viewer = Meeting::VIEWER_PARTICIPANT;
     }
   }

Они настраивают свойства $owner_id и $viewer в модели Meeting.

Каждая встреча, которую вы создаете, вероятно, будет иметь разные характеристики. Иногда вы хотите ограничить участников предложением предлагать разные времена и места или уточнять детали. В других случаях вам будет все равно. Когда мы в конечном итоге создадим шаблоны собраний для повторного использования общих типов собраний, например, утренних кофейных бизнес-встреч, в шаблонах, вероятно, также потребуется сохранить такие настройки. Как мы должны это реализовать?

Во-первых, я хотел бы создать набор настроек по умолчанию для пользователей в отношении встреч, которые они создают.

Затем я создам набор MeetingSettings для каждой встречи. Когда собрание создается с нуля, оно наследует настройки по умолчанию от пользователя, который его создает. Редактирование настроек для отдельных встреч можно отложить на потом.

В будущем, когда мы внедрим шаблоны собраний, мы добавим настройки собраний и для шаблонов. Однако это также может быть отложено.

Вот настройки, которые мы хотели бы создать, чтобы начать:

  • Разрешить участникам добавлять места.
  • Разрешить участникам добавлять даты и время.
  • Разрешить участникам выбирать места.
  • Разрешить участникам выбирать даты и время.
  • Разрешить участникам завершить встречу.

Поскольку мы все возвращаемся в сериал через некоторое время из-за отсутствия моего здоровья, я немного подробнее расскажу о некоторых работах.

Сначала мы создадим миграцию настроек собрания:

1
2
3
4
5
$ ./yii migrate/create meeting_setting_table
Yii Migration Tool (based on Yii v2.0.7)
 
Create new migration ‘/Users/Jeff/Sites/mp/console/migrations/m160401_203412_meeting_setting_table.php’?
New migration created successfully.

Это создает файл миграции, нам нужно написать код, который строит таблицу базы данных в соответствии с нашей схемой:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<?php
use yii\db\Schema;
use yii\db\Migration;
 
class m160401_203412_meeting_setting_table extends Migration
{
  public function up()
   {
       $tableOptions = null;
       if ($this->db->driverName === ‘mysql’) {
           $tableOptions = ‘CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE=InnoDB’;
       }
 
       $this->createTable(‘{{%meeting_setting}}’, [
           ‘id’ => Schema::TYPE_PK,
           ‘meeting_id’ => Schema::TYPE_INTEGER.’
           ‘participant_add_place’ => Schema::TYPE_SMALLINT .
           ‘participant_add_date_time’ => Schema::TYPE_SMALLINT .
           ‘participant_choose_place’ => Schema::TYPE_SMALLINT .
           ‘participant_choose_date_time’ => Schema::TYPE_SMALLINT .
           ‘participant_finalize’ => Schema::TYPE_SMALLINT .
           ‘created_at’ => Schema::TYPE_INTEGER .
           ‘updated_at’ => Schema::TYPE_INTEGER .
       ], $tableOptions);
       $this->addForeignKey(‘fk_meeting_setting’, ‘{{%meeting_setting}}’, ‘meeting_id’, ‘{{%meeting}}’, ‘id’, ‘CASCADE’, ‘CASCADE’);
   }
 
   public function down()
   {
       $this->dropForeignKey(‘fk_meeting_setting’, ‘{{%meeting_setting}}’);
       $this->dropTable(‘{{%meeting_setting}}’);
   }
}

По сути, каждое собрание имеет ряд MeetingSettings с логическими свойствами для различных вариантов участников, которые я показал выше.

Затем мы инструктируем Yii перенести вверх и создать таблицу:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
$ ./yii migrate/up
Yii Migration Tool (based on Yii v2.0.7)
 
Total 1 new migration to be applied:
    m160401_203412_meeting_setting_table
 
Apply the above migration?
*** applying m160401_203412_meeting_setting_table
    > create table {{%meeting_setting}} … done (time: 0.010s)
    > add foreign key fk_meeting_setting: {{%meeting_setting}} (meeting_id) references {{%meeting}} (id) … done (time: 0.011s)
*** applied m160401_203412_meeting_setting_table (time: 0.040s)
 
1 migration was applied.
Migrated up successfully.

Наш внешний ключ создает связь между таблицей Meeting и таблицей MeetingSetting.

Далее мы будем использовать Yii’s Gii для автоматической генерации кода для просмотра и обновления настроек. Для начала я возвращаюсь на http: // localhost: 8888 / mp / index.php / gii / . Начнем с генерации модели:

Настройка вида собрания - Yiis Gii Model Generator для настройки собрания

Затем мы сгенерируем код создания, чтения, обновления, удаления (CRUD):

Настройка вида встречи - Gii CRUD Generator

Поскольку сейчас нам не нужен весь этот код, Gii позволяет нам выбирать только те функции, которые нам нужны: контроллер , представление, _form и update :

Настройка вида собрания - ограничение количества файлов для перезаписи вручную

Gii показывает вам список файлов, которые он создает с каждым шагом:

Настройка просмотра собрания - список сгенерированных файлов Gii

Но как насчет пользовательских настроек по умолчанию? По сути, их типичные предпочтения встречи?

Для этого мы добавим свойства параметров параллельной встречи в таблицу user_setting . Опять же, мы создадим миграцию:

1
2
3
4
5
$ ./yii migrate/create extend_user_setting_table
Yii Migration Tool (based on Yii v2.0.7)
 
Create new migration ‘/Users/Jeff/Sites/mp/console/migrations/m160401_210852_extend_user_setting_table.php’?
New migration created successfully.

Вот столбцы, которые мы должны добавить:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class m160401_210852_extend_user_setting_table extends Migration
{
  public function up()
  {
    $tableOptions = null;
    if ($this->db->driverName === ‘mysql’) {
        $tableOptions = ‘CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE=InnoDB’;
    }
     
    $this->addColumn(‘{{%user_setting}}’,’participant_add_place’,Schema::TYPE_SMALLINT.’ NOT NULL’);
    $this->addColumn(‘{{%user_setting}}’,’participant_add_date_time’,Schema::TYPE_SMALLINT.’ NOT NULL’);
    $this->addColumn(‘{{%user_setting}}’,’participant_choose_place’,Schema::TYPE_SMALLINT.’ NOT NULL’);
    $this->addColumn(‘{{%user_setting}}’,’participant_choose_date_time’,Schema::TYPE_SMALLINT.’ NOT NULL’);
    $this->addColumn(‘{{%user_setting}}’,’participant_finalize’,Schema::TYPE_SMALLINT.’ NOT NULL’);
  }
 
  public function down()
  {
    $this->dropColumn(‘{{%user_setting}}’,’participant_finalize’);
    $this->dropColumn(‘{{%user_setting}}’,’participant_choose_date_time’);
    $this->dropColumn(‘{{%user_setting}}’,’participant_choose_place’);
    $this->dropColumn(‘{{%user_setting}}’,’participant_add_date_time’);
    $this->dropColumn(‘{{%user_setting}}’,’participant_add_place’);
  }
}

Затем мы запустим миграцию:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
$ ./yii migrate/up
Yii Migration Tool (based on Yii v2.0.7)
 
Total 1 new migration to be applied:
    m160401_210852_extend_user_setting_table
 
Apply the above migration?
*** applying m160401_210852_extend_user_setting_table
    > add column participant_add_place smallint NOT NULL to table {{%user_setting}} … done (time: 0.012s)
    > add column participant_add_date_time smallint NOT NULL to table {{%user_setting}} … done (time: 0.007s)
    > add column participant_choose_place smallint NOT NULL to table {{%user_setting}} … done (time: 0.010s)
    > add column participant_choose_date_time smallint NOT NULL to table {{%user_setting}} … done (time: 0.009s)
    > add column participant_finalize smallint NOT NULL to table {{%user_setting}} … done (time: 0.009s)
*** applied m160401_210852_extend_user_setting_table (time: 0.061s)
 
1 migration was applied.
Migrated up successfully.

Вместо принудительной перезаписи нашей модели UserSetting.php с помощью Gii, мы будем использовать опцию diff для Gii:

Настройка вида собрания - использование Giis diff вместо перезаписи

И оттуда мы вручную выберем новые дополнения к файлу и вставим их в:

Настройка просмотра собрания - просмотр различий для копирования и вставки необходимых изменений

Функционально мы добавим вкладку настроек собрания на страницу свойств Обновить ваши настройки :

Настройка просмотра собрания - пользовательские настройки с двумя существующими вкладками

Мы добавим следующий код в /frontend/views/user-setting/_form.php для поддержки наших новых свойств:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
<div class=»col-md-8″>
        <!— Nav tabs —>
        <ul class=»nav nav-tabs» role=»tablist»>
          <li class=»active»><a href=»#general» role=»tab» data-toggle=»tab»><?= Yii::t(‘frontend’,’General Settings’) ?></a></li>
          <li><a href=»#preferences» role=»tab» data-toggle=»tab»><?= Yii::t(‘frontend’,’Meeting Preferences’) ?></a></li>
          <li><a href=»#photo» role=»tab» data-toggle=»tab»><?= Yii::t(‘frontend’,’Upload Photo’) ?></a></li>
        </ul>
        <!— Tab panes —>
        <div class=»tab-content»>
           …
        </div>
          <div class=»tab-pane vertical-pad» id=»preferences»>
            <?= $form->field($model, ‘participant_add_place’)->checkbox([‘uncheck’ => $model::SETTING_NO, ‘checked’ => $model::SETTING_YES]);
            <?= $form->field($model, ‘participant_add_date_time’)->checkbox([‘uncheck’ => $model::SETTING_NO, ‘checked’ => $model::SETTING_YES]);
            <?= $form->field($model, ‘participant_choose_place’)->checkbox([‘uncheck’ => $model::SETTING_NO, ‘checked’ => $model::SETTING_YES]);
            <?= $form->field($model, ‘participant_choose_date_time’)->checkbox([‘uncheck’ => $model::SETTING_NO, ‘checked’ => $model::SETTING_YES]);
            <?= $form->field($model, ‘participant_finalize’)->checkbox([‘uncheck’ => $model::SETTING_NO, ‘checked’ => $model::SETTING_YES]);
 
           </div> <!— end of upload meeting-settings tab —>
           <div class=»tab-pane vertical-pad» id=»photo»>
       …

Вот обновленная форма:

Настройка просмотра собрания - пользовательские настройки с настройками встречи

Всякий раз, когда пользователь создает новое собрание, мы должны загрузить его настройки по умолчанию и скопировать их в настройки отдельного собрания. initializeMeetingSetting вызывается при создании нового собрания для этого:

01
02
03
04
05
06
07
08
09
10
11
12
public function initializeMeetingSetting($meeting_id,$owner_id) {
     // load meeting creator (owner) user settings to initialize meeting_settings
     $user_setting = UserSetting::find()->where([‘user_id’ => $owner_id])->one();
     $meeting_setting = new MeetingSetting();
     $meeting_setting->meeting_id = $meeting_id;
     $meeting_setting->participant_add_place=$user_setting->participant_add_place;
     $meeting_setting->participant_add_date_time=$user_setting->participant_add_date_time;
     $meeting_setting->participant_choose_place=$user_setting->participant_choose_place;
   $meeting_setting->participant_choose_date_time=$user_setting->participant_choose_date_time;
     $meeting_setting->participant_finalize=$user_setting->participant_finalize;
     $meeting_setting->save();
   }

Установив настройки собрания, мы готовы перейти к тому, что на самом деле составляет основную часть сегодняшней работы, настроив виды собраний для владельца и участника.

Теперь давайте рассмотрим состояние нашего представления собрания на основе создателя или владельца собрания. Вот приглашение на встречу, которое я недавно создал, чтобы пригласить моего друга Роба выпить:

Настройка вида встречи - текущий вид встречи

Перед включением функции отправки и завершения необходимо пригласить человека и хотя бы одно место и время. Если есть более одного места и времени, необходимо выбрать один из них для завершения совещания.

Кнопки собрания Отмена (значок X) и Изменить (значок карандаша) также включены для создателей.

Для MVP мы сначала ограничиваем приглашения на собрания только для одного участника. Поэтому, как только человек был приглашен, кнопка « Добавить» (значок «плюс») отключена.

Создатель может добавить места и дату и время до максимума нашего сайта (например, семь на одно собрание), и они могут указать их наличие и принятие. И, наконец, когда их несколько, они могут выбрать, какое место и время будут использованы.

Создатель всегда может добавить заметки к встрече. Заметки позволяют создателю и участникам общаться друг с другом.

В конечном итоге мы приложим основную часть нашей работы к улучшению функциональности AJAX, чтобы по мере того, как владелец выбирал места и время, кнопки «Отправить» и «Завершить» были правильно включены (или отключены в некоторых случаях).

Вот пример встречи с двумя возможными временами. Кнопка « Завершить» не может быть включена, пока не будет выбран один раз:

Настройка вида собрания - другой сценарий вида собрания

После того, как выбор сделан, мы бы хотели включить кнопку « Завершить» через AJAX, чтобы избавить пользователя от обновления страницы.

Когда мы просматриваем приглашение с точки зрения участника, у нас гораздо меньше начальных возможностей:

Настройка вида собрания - вид участника

Участник может отменить (значок X) свое посещение собрания и указать, приемлемы ли для него места и время, но он не может выбрать окончательное место или завершить собрание. Кроме того, данные в столбцах « Вы» и « Они» теперь переключаются. И панель участника скрыта, так как она не нужна.

Кроме того, скажем, собрание было создано с настройками, которые позволяли участнику выбирать место, дату и время, но не завершали собрание. Это должно выглядеть так:

Настройка просмотра собрания - представление участника с выбором участника

Так как есть только одно Место, Herkimer Coffee , вам не нужно выбирать селектор. Но там, где есть два возможных времени, теперь вы можете видеть селекторы выбора. Тем не менее, нет кнопки Завершить.

Оказалось, что для поддержки всего этого потребовалось много нового кода для обновления системы, но это начинает проникать в суть продукта — опыт планирования встреч пользователей. Я проведу вас через несколько изменений, которые были необходимы.

На панелях времени и места встречи нам нужно использовать настройки встречи, чтобы определить, нужно ли показывать селектор выбора. В представлении _panel.php это выглядит так:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
<table class=»table»>
    <thead>
    <tr class=»small-header»>
      <td></td>
      <td ><?=Yii::t(‘frontend’,’You’) ?></td>
      <td ><?=Yii::t(‘frontend’,’Them’) ?></td>
      <td >
        <?php
         if ($timeProvider->count>1 && ($isOwner || $model->meetingSettings->participant_choose_date_time)) echo Yii::t(‘frontend’,’Choose’);
        ?>
       </td>
   </tr>
   </thead>
   <?= ListView::widget([
          ‘dataProvider’ => $timeProvider,
          ‘itemOptions’ => [‘class’ => ‘item’],
          ‘layout’ => ‘{items}’,
          ‘itemView’ => ‘_list’,
          ‘viewParams’ => [‘timeCount’=>$timeProvider->count,’isOwner’=>$isOwner,’participant_choose_date_time’=>$model->meetingSettings[‘participant_choose_date_time’]],
      ]) ?>
 </table>

Мы проверяем настройки участников и передаем их в качестве параметра в последующее представление _list.php, которое выглядит следующим образом:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<td style>
     <?php
     if ($timeCount>1) {
       if ($model->status == $model::STATUS_SELECTED) {
           $value = $model->id;
       } else {
         $value = 0;
       }
       if ($isOwner || $participant_choose_date_time) {
         // value has to match for switch to be on
         echo SwitchInput::widget([
             ‘type’ => SwitchInput::RADIO,
             ‘name’ => ‘time-chooser’,
             ‘items’ => [
                 [ ‘value’ => $model->id],
             ],
             ‘value’ => $value,
             ‘pluginOptions’ => [ ‘size’ => ‘mini’,’handleWidth’=>60,’onText’ => ‘<i class=»glyphicon glyphicon-ok»></i>’,’offText’=>'<i class=»glyphicon glyphicon-remove»></i>’],
             ‘labelOptions’ => [‘style’ => ‘font-size: 12px’],
         ]);
       }
     }
     ?>
 </td>

Если представление является создателем или участнику разрешено выбрать последний раз, они увидят что-то вроде этого, возможность Выбрать в правом столбце:

Настройка вида собрания - выбор выбора для времени дат

Я создал функции canSend() и canFinalize() , которые обычно поддерживают код и запросы AJAX для определения активного состояния кнопок отправки и завершения.

Вот canSend() :

01
02
03
04
05
06
07
08
09
10
11
12
13
14
public function canSend($sender_id) {
      // check if an invite can be sent
      // req: a participant, at least one place, at least one time
      if ($this->owner_id == $sender_id
       && count($this->participants)>0
       && count($this->meetingPlaces)>0
       && count($this->meetingTimes)>0
       ) {
        $this->isReadyToSend = true;
      } else {
        $this->isReadyToSend = false;
      }
      return $this->isReadyToSend;
     }

Организатор не может отправить приглашение на собрание, пока не будут указаны участники, места и время.

Вот canFinalize() :

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
public function canFinalize($user_id) {
       $this->isReadyToFinalize = false;
       // check if meeting can be finalized by viewer
       // check if overall meeting state can be sent by owner
        if (!$this->canSend($this->owner_id)) return false;
         $chosenPlace = false;
         if (count($this->meetingPlaces)==1) {
           $chosenPlace = true;
         } else {
           foreach ($this->meetingPlaces as $mp) {
             if ($mp->status == MeetingPlace::STATUS_SELECTED) {
               $chosenPlace = true;
               break;
             }
           }
         }
         $chosenTime = false;
         if (count($this->meetingTimes)==1) {
           $chosenTime = true;
         } else {
           foreach ($this->meetingTimes as $mt) {
             if ($mt->status == MeetingTime::STATUS_SELECTED) {
                 $chosenTime = true;
                 break;
             }
           }
         }
         if ($this->owner_id == $user_id ||
         $this->meetingSettings->participant_finalize) {
           if ($chosenPlace && $chosenTime) {
             $this->isReadyToFinalize = true;
           }
         }
       return $this->isReadyToFinalize;
     }

Сначала проверяется, может ли собрание быть отправлено, потому что если нет, оно не может быть завершено. Затем он проверяет, выбраны ли место и время. Затем он проверяет, является ли средство просмотра организатором, или настройки собрания позволяют участнику завершить собрание.

По сути, после внесения изменений вы увидите состояние изменений кнопок « Отправить» и « Завершить» :

Настройка вида собрания - Панель команд с отправкой и завершением

В view.php собрания я включил JavaScript для поддержки обновлений AJAX для состояния кнопок «Отправить» и «Завершить», когда пользователи изменяют настройки своего собрания. Когда выбор мест и времени сделан, refreshSend() и refreshFinalize() , и кнопки соответствующим образом модифицируются:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
<?php
if (isset(Yii::$app->params[‘urlPrefix’])) {
  $urlPrefix = Yii::$app->params[‘urlPrefix’];
  } else {
    $urlPrefix =»;
  }
$script = <<< JS
function refreshSend() {
  $.ajax({
     url: ‘$urlPrefix/meeting/cansend’,
     data: {id: $model->id, ‘viewer_id’: $viewer},
     success: function(data) {
       if (data)
         $(‘#actionSend’).removeClass(«disabled»);
        else
        $(‘#actionSend’).addClass(«disabled»);
       return true;
     }
  });
}
 
function refreshFinalize() {
  $.ajax({
     url: ‘$urlPrefix/meeting/canfinalize’,
     data: {id: $model->id, ‘viewer_id’: $viewer},
     success: function(data) {
       if (data)
         $(‘#actionFinalize’).removeClass(«disabled»);
        else
        $(‘#actionFinalize’).addClass(«disabled»);
       return true;
     }
  });
}
 
JS;
$position = \yii\web\View::POS_READY;
$this->registerJs($script, $position);
?>

В текущем пользовательском интерфейсе мы показываем выбор места и времени зрителя в крайнем левом или первом столбце. Код должен быть настроен, чтобы изменить это, когда участники просматривают:

Настройка вида собрания - столбцы «Ты и они» для данных выбора

Для поддержки отображения разных данных в столбцах «Вы» и «Их» представления собрания для «Времена и места» необходимо обновить файлы _list.php времени собрания и места встречи, чтобы динамически определить, какие данные отображать:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
<td style>
   <?php
      if ($isOwner) {
        showTimeOwnerStatus($model,$isOwner);
      } else {
        showTimeParticipantStatus($model,$isOwner);
      }
   ?>
 </td>
 <td style>
     <?php
       if (!$isOwner) {
          showTimeOwnerStatus($model,$isOwner);
        } else {
          showTimeParticipantStatus($model,$isOwner);
        }
     ?>
 </td>

На данный момент я поместил эти функции в представление _panel.php, которое вызывает _list.php, так как они полагаются на включение виджета SwitchInput в контекст:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
<?php
use \kartik\switchinput\SwitchInput;
 
  function showTimeOwnerStatus($model,$isOwner) {
    foreach ($model->meetingTimeChoices as $mtc) {
      if ($mtc->user_id == $model->meeting->owner_id) {
          if ($mtc->status == $mtc::STATUS_YES)
            $value = 1;
          else
            $value =0;
            echo SwitchInput::widget([
            ‘type’ => SwitchInput::CHECKBOX,
            ‘name’ => ‘meeting-time-choice’,
            ‘id’=>’mtc-‘.$mtc->id,
            ‘value’ => $value,
            ‘disabled’ => !$isOwner,
            ‘pluginOptions’ => [‘size’ => ‘mini’,’onText’ => ‘<i class=»glyphicon glyphicon-ok»></i>’,’offText’=>'<i class=»glyphicon glyphicon-remove»></i>’,’onColor’ => ‘success’,’offColor’ => ‘danger’,],
            ]);
      }
    }
  }
 
  function showTimeParticipantStatus($model,$isOwner) {
    foreach ($model->meetingTimeChoices as $mtc) {
      if (count($model->meeting->participants)==0) break;
      if ($mtc->user_id == $model->meeting->participants[0]->participant_id) {
          if ($mtc->status == $mtc::STATUS_YES)
            $value = 1;
          else if ($mtc->status == $mtc::STATUS_NO)
            $value =0;
          else if ($mtc->status == $mtc::STATUS_UNKNOWN)
            $value =-1;
          echo SwitchInput::widget([
            ‘type’ => SwitchInput::CHECKBOX,
            ‘name’ => ‘meeting-time-choice’,
            ‘id’=>’mtc-‘.$mtc->id,
            ‘tristate’=>true,
            ‘indeterminateValue’=>-1,
            ‘indeterminateToggle’=>false,
            ‘disabled’=>$isOwner,
            ‘value’ => $value,
            ‘pluginOptions’ => [‘size’ => ‘mini’,’onText’ => ‘<i class=»glyphicon glyphicon-ok»></i>’,’offText’=>'<i class=»glyphicon glyphicon-remove»></i>’,’onColor’ => ‘success’,’offColor’ => ‘danger’,],
        ]);
      }
    }
  }
?>

В конечном счете, в этот код необходимо внести множество улучшений. Местами я делаю AJAX-вызовы на сервер два или три раза, когда я могу более эффективно кодировать их в один запрос. В других местах я могу делать больше локально с помощью JavaScript. И пользовательский интерфейс должен будет продолжать улучшаться, и код должен будет измениться, чтобы приспособиться к этому. Но с функциональной точки зрения сегодняшняя работа представляет собой большой общий прогресс в направлении MVP.

После настройки параметров собрания и просмотра требований для организаторов и участников я готов приступить к отправке первого приглашения. В следующем эпизоде ​​будет рассмотрено отправка приглашения участнику по электронной почте, а также реализация внешнего вида содержимого, функциональных командных ссылок в письме и управление разрешениями для пользователей, которые еще не зарегистрировались. Следите за будущими уроками в нашей серии «Построение стартапа с помощью PHP» — это становится захватывающим!

Пожалуйста, не стесняйтесь добавлять свои вопросы и комментарии ниже; Я обычно участвую в обсуждениях. Вы также можете связаться со мной в Twitter @reifman .