Paggawa ng Inyong Panimula: Paunang mga Utos sa Pag-iiskedyul
() translation by (you can also view the original English article)



Ang tutorial na ito ay bahagi ngserye tungkol sa pagbuo ng iyong startup gamit ang PHP sa Envato Tuts+. Sa seryeng ito, gagabayan ko kayo sa paglulunsad ng isang startup mula sa konsepto sa kasalukuyan gamit ang aking Meeting Planner app bilang isang makatotohanan na halimbawa. Bawat hakbang sa kahabaan ng proseso, ibibigay ko ang open-source code ng aking Meeting Planner app bilang halimbawa kung saan maaari mong malaman ang pinagmulan. Tatalakayin ko din angmga isyu tungkol sa negosyo kung meron tayong madaanan.
Pagpapalawak ng mga Pagpipilian sa Pagtatakda
Habang ang unang bahagi ng pagsusuri ng Tagaplano ng Pagpupulong ay nagsisimula, ang pinakamalinaw na puwang sa tampok ay ang kawalan ng kakayahan na baguhin ang pagpupulong pagkatapos na ito ay maitakda na. Ngunit mayroon pang ibang mga tampok na nawawala, katulad ng muling pagpapadala ng imbitasyon sa na nawala sa email, muling pagtatakda ng pagpupulong ng ganap, o kaya ang kawalan ng kakayahan na Makita at mabago ang mga setting ng control na pinili ng tagapag-organisa.
Kawili-wiling nasimulan kong mapagtanto na ang kakayahan na maiayos ang mga pagpupulong nang madali pagkatapos na ito ay maitakda ay maaaring makabuo o makasire ng tatak ng Tagaplano ng Pagpupulong. Halimbawa, madaming pakikipagkapwang pag-iininyero sa pag-aayos ng katatapos itakdang pagpupulong. Madalas, kailangan mong itanong sa (mga) kalahok kung ayos lamang na baguhin ang oras o lugar. Maaaring gusto mo lamang magpulong ng mas maaaga ng 15 minuto o kaya sa susunod na araw sa parehong oras at lugar. Ngunit hindi mo maaaring laging gawin ang mga pagbabagong ito ng walang pahintulot.
Ang pagpapanatiling madaling intindihin at payak gamitin ang site kasama ang lahat ng kakayahan nito ang aking pangunahing direktiba. Paano ako makakapagdagdag ng pataas na bilang ng mga tampok nang hindi kakalat ang interface ng gagamit o hindi masyadong itatago ang mga ito. Paano ito gagana sa interface ng parehong mobile at desktop?
Sa tutoryal ngayon, tatalakayin ko ang pagpapalawak ng bar ng nabigasyon sa pamamagitan ng paggamit ng Bootstrap at ang mga batayan ng paggawa ng ilan sa mga paunang mga tampok ng pag-iiskedyul sa loob ng Tagaplano ng Pagpupulong. Sa susunod na lingo, irerepaso ko ang paggawa ng mas kumplikadong tampok para sa mga kalahok na hihiling ng (mga) pagbabago at para sa iba na tatanggap o tatanggi sa mga ito.
Inaasahan ko na susubukan ninyo lahat ng bagong tampok sap ag-iiskedyul sa live na site at ibabahagi ninyo ang inyong mga saloobin at katugunan sa mga komento sa ibaba. Kung mayroon kayong mga katanungan tungkol sa tutoryal o aplikasyon nito, ako ay sumasagot sa talakayan sa ibaba, at maaari din kayong makipag-ugnayan sa akin sa @reifman sa Twitter. Ako ay laging bukas para sa mga bagong tampok na ideya para sa Meeting Planner at pati na rin sa mga mungkahi para sa mga susunod na episode ng mga serye.
Bilang paalala, ang lahat ng mga code para sa Meeting Planner ay nakasulat sa Yii2 Framework para sa PHP. Kung gusto mong matuto nang iba pa tungkol sa Yii2, tingnan ang aming parallel series Programming Sa Yii2.
Pagpapalawak sa Bar ng Nabigasyon
Una, tingnan nating kung paano palawakin ang umiiral ng bar ng nabigasyon. Heto ang listahan ng mga tampok na balak kong idagdag:
- Pagpayag na magbago ang mga lugar, petsa at oras ng pagpupulong pagkatapos na ito ay matapos.
- Paghiling ng maliliit ng mga pagbabago sa pagpupulong, katulad ng maaari ba tayong magkita ng mas maaga ng isang oras? O kaya ay sa ibang iminungkahing lugar?
- Paglilipat ng iskedyul ng mismong pagpupulong na pareho ang mga kalahok at mga lugar.
- Pag-uulit ng pagpupulong gamit ang mga kalahok, mga lugar, mga araw ng lingo at mga oras ng araw mula sa nakaraang pagpupulong upang mapadali ang pag-iiskedyul ng bagong pagpupulong.
- Pagpapakita sa mga kalahok ng sunod-sunod na kasaysayan ng lahat ng mga aktibidad sa pagpaplano para sa pagpupulong.
- Pagtingin at pag-update sa mga setting para sa pagpupulong.
Katulad ng nakikita niyo, hindi lamang mayroong maraming pagpapaandar na kailangang gawin, ngunit wala rin akong malinaw na sapantaha kung saan ito ilalagay sa interface ng gagamit nang hindi lilikha ng gulo.
Ang bar ng utos at kailangan ding magbago nang ayon sa kalagayan ng pagpupulong. Ang mga pagpupulong na nasa pagpaplanong bahagi ay may ibang mga pagpipilian sa nakabitin, kumpirmado o nakalipas na tapos ng mga pagpupulong.
Naunang mga UX na Ideya na Nagdala pabalik sa Bootstrap
Ang unang ideya ko ay magbigay ng maliit na link ng Paunang mga Setting na magpapakita sa nakatagong bar ng utos. Nag-eksperimento dito sa simula, ngunit hindi ito kalugod-lugod tingnan.
Tapos, nirepaso ko ang dokumentasyon ng Bootstrap at natagpuan ko ang dropdown combo na kahon:



Nagustuhan ko kung paano ito umandar. Kaya nagpasya ako na ilagay ang karamihan sa mga paunang utos sa nakaayos sa kaliwa na dropdown na button.
Heto ang halimbawa kung ano ang hitsura nito sa pagpaplanong bahagi ng pagpupulong:



Pansinin na ang bootstap ay nag-aalok ng uri ng mga dropup na menu. Ang bar ng utos na nakalagay sa ilalim ng pahina ay gumagamit ng dropup katulad ng sumusunod:
1 |
/* the partial position knows to set the dropclass variable up or down */
|
2 |
echo $this->render('_command_bar_past', [ |
3 |
'model'=>$model, |
4 |
'isPast'=>true, |
5 |
'dropclass'=>'dropup', |
6 |
'isOwner' => $isOwner, |
7 |
]);
|
8 |
|
9 |
/* the resulting view applies the dropclass */
|
10 |
<div class="command-bar"> |
11 |
<div class="row"> |
12 |
<div class="col-xs-4"> |
13 |
<div class="<?= $dropclass ?>" > |
14 |
<button class="btn btn-default dropdown-toggle" type="button" id="dropdownMenu1" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true"> |
15 |
<?= Yii::t('frontend','Options');?> |
16 |
<span class="caret"></span> |
17 |
</button>
|
18 |
<ul class="dropdown-menu" aria-labelledby="dropdownMenu1"> |
19 |
<?php
|
20 |
if (!$isPast && ($model->viewer == Meeting::VIEWER_ORGANIZER || $meetingSettings->participant_reopen)) { |
21 |
?>
|
22 |
<li><?= Html::a(Yii::t('frontend', 'Make changes'), ['reopen','id'=>$model->id], |
23 |
['title'=>Yii::t('frontend','tbd')]); ?></li> |
Lumikha din ako ng paunang kita sa mga file
na gagawin ayon sa kalagayan ng pagpupulong. Halimbawa sa /frontend/views/meeting/view_confirmed.php, makikita niyo kahit
alin sa _command_bar_past.php
o _command_bar_confirmed.php
kasama ang paunang bahagi:
1 |
<?php
|
2 |
if ( $model->status >= $model::STATUS_COMPLETED) { |
3 |
...
|
4 |
echo $this->render('_command_bar_past', [ |
5 |
'model'=>$model, |
6 |
'isPast'=>true, |
7 |
'dropclass'=>'dropdown', |
8 |
'isOwner' => $isOwner, |
9 |
]);
|
10 |
} else { |
11 |
echo $this->render('_command_bar_confirmed', [ |
12 |
'model'=>$model, |
13 |
'meetingSettings' => $meetingSettings, |
14 |
'showRunningLate'=>$showRunningLate, |
15 |
'isPast'=>$isPast, |
16 |
'dropclass'=>'dropdown', |
17 |
'isOwner' => $isOwner, |
18 |
]);
|
19 |
}
|
20 |
?>
|
Pag-alam ng Access sa mga Utos para sa Iba’t ibang Titingin
Hindi ko gusto payagan lahat na makita ang lahat ng mg utos. Ang mga taga-organisa ay makakakita ng mas maraming mg autos kaysa sa mga kalahok, ngunit ang mga setting ng pagpupulong ay kadalasang binibigyan din sila ng access.
Heto ang halimbawa ng pag-alam kung ipapakita ang pagpipilian upang muling mabuksan ang pagpupulong at gumawa ng mga pagbabago dito na parang nasa pagpaplanong bahagi pa din ito:
1 |
<ul class="dropdown-menu" aria-labelledby="dropdownMenu1"> |
2 |
<?php
|
3 |
if (!$isPast && ($model->viewer == Meeting::VIEWER_ORGANIZER |
4 |
|| $meetingSettings->participant_reopen)) { |
5 |
?>
|
6 |
<li><?= Html::a(Yii::t('frontend', 'Make changes'), ['reopen','id'=>$model->id], |
7 |
['title'=>Yii::t('frontend','tbd')]); ?></li> |
8 |
Ang pagpipilian ay kabilang sa dropdown na menu ng Bootstrap kung ang pagpupulong ay hindi pa lumalampas sa simulang petsa nito at ang titingin ay ang taga-organisa o pinayagan ng taga-organisa ang mga kalahok na gumawa ng mga pagbabago.
Ngayon, pumunta na tayo sa paggawa ng ilan sa mga pagpapaandar para sa iba’t ibang mga utos na ito.
Paggawa ng Paunang mga Utos sa Pag-iiskedyul
Hindi possible na matalakay ang lahat sa bagong gawain na kasama nitong mga tampok sa pag-iiskedyul. Para sa kaiksian, tatalakayin ko lamang ang mga batayan at kahit anong walang kaparehong aspeto ng iba’t-ibang mg autos.
Bawat Tampok ay Mas Matagal na Ngayon
Pagkatapos ng pagpapatupad ng mas malalalim na tampok sa seguridad sa loob ng Tagaplano ng Pagpupulong, sinubukan kong umayon sa mas mahigpit na pamantayan sa pagkokodigo habang nagdadagdag ako ng mga bagong tampok. Gumugugol ako ng mas maraming oras sa access ng nagkokontrol, pagsusuri ng modelong access, at pagtatakda ng bilis.
Gayundin, ang beta na inilabas ay susuporta sa madaming mga kalahok sa pagpupulong, kaya kailangan kong iarkitekto ang code na iyon ang nasa isip habang gumagawa ako.
Sa kabuuan, lahat ng ginagawa ko ay medyo mas matagal kaysa noong sa mabilis na tularang paraan.
Habang ginagawa ko ang iba’t ibang mga tampok sa pagpupulong na ito, madalas kong maramdaman ang lumaking trabaho na idinagdag ko sa codebase. Mapapansin niyo ang mga tsek na ito sa code sa ibaba.
Mayroon ding atensyon sa tala ng makasaysayang Pagpupulong na gagawin na naming nakikita. Kaya lahat ng aksyon ay madalas nangangailangan ng talaan. At ang mga talaan ay makakatulong sa pagsuporta sa pagtatakda ng bilis.
Paglikha ng mga Pagbabago sa Pagpupulong
Isang madaling paraan upang payagan ang mga pagbabago sa pagpupulong na natapos na ay ang payagan lamang ang taga-organisa na muling makapagbukas nito, ibalik ito sa pagpaplanong bahagi. Tapos, maaari nilang idagdag ang petsa, oras at lugar, pumili ng bago, at tapusing mula ang pagpupulong.
Gusto ko ding magbigay ng kapangyarihan ang taga-organisa sa kanilang mga kalahok upang gawin ito. Nangangailangan ito sa katapusan ng pagbuo ng kakayahan upang makita at maupdate bawat mga setting ng pagpupulong.
Nagdagdag ako ng mga setting upang payagan ang mga kalahok alinman sa humiling ng mga pagbabago sa taga-organisa o kaya ay gawin ang mga ito ng direkta.
Kapag ang pagpupulong ay nilikha, ang mga setting ay sinimulan sa nakatakdang mga setting ng gumagamit:
1 |
public function initializeMeetingSetting($meeting_id,$owner_id) { |
2 |
$checkMtgStg = MeetingSetting::find()->where(['meeting_id' => $meeting_id])->one(); |
3 |
if (is_null($checkMtgStg)) { |
4 |
// load meeting creator (owner) user settings to initialize meeting_settings
|
5 |
UserSetting::initialize($owner_id); // if not initialized |
6 |
$user_setting = UserSetting::find()->where(['user_id' => $owner_id])->one(); |
7 |
$meeting_setting = new MeetingSetting(); |
8 |
$meeting_setting->meeting_id = $meeting_id; |
9 |
$meeting_setting->participant_add_place=$user_setting->participant_add_place; |
10 |
$meeting_setting->participant_add_date_time=$user_setting->participant_add_date_time; |
11 |
$meeting_setting->participant_choose_place=$user_setting->participant_choose_place; |
12 |
$meeting_setting->participant_choose_date_time=$user_setting->participant_choose_date_time; |
13 |
$meeting_setting->participant_finalize=$user_setting->participant_finalize; |
14 |
$meeting_setting->participant_reopen=$user_setting->participant_reopen; |
15 |
$meeting_setting->participant_request_change=$user_setting->participant_request_change; |
16 |
$meeting_setting->save(); |
17 |
}
|
18 |
}
|
Makikita mo ang mga resulta ng bagong tagakontrol at maia-update ang makikita para sa MeetingSettings sa ibaba:



At heto/ frontend/controllers/MeetingController.php's actionReopen()
:
1 |
public function actionReopen($id) { |
2 |
$m = $this->findModel($id); |
3 |
$m->setViewer(); |
4 |
// also check reopen()
|
5 |
if ($m->viewer == Meeting::VIEWER_ORGANIZER || $m->meetingSettings->participant_reopen) { |
6 |
if ($m->reopen()) { |
7 |
Yii::$app->getSession()->setFlash('success', Yii::t('frontend','The meeting has now been reopened so you can make changes.')); |
8 |
} else { |
9 |
Yii::$app->getSession()->setFlash('error', Yii::t('frontend','Sorry, you are not allowed to reopen a meeting this many times. Try creating a new meeting.')); |
10 |
}
|
11 |
} else { |
12 |
Yii::$app->getSession()->setFlash('error', Yii::t('frontend','Sorry, you are not allowed to do this.')); |
13 |
}
|
14 |
return $this->redirect(['view', 'id' => $id]); |
15 |
}
|
At heto ang Meeting.php na modelong code upang ilipat ang pagpupulong pabalik sa pagpaplanong bahagi:
1 |
public function reopen() { |
2 |
// when organizer or participant with permission asks to make changes
|
3 |
if (MeetingLog::withinActionLimit($this->id,MeetingLog::ACTION_REOPEN,Yii::$app->user->getId(),7)) { |
4 |
$this->status = Meeting::STATUS_SENT; |
5 |
$this->update(); |
6 |
$this->increaseSequence(); |
7 |
MeetingLog::add($this->id,MeetingLog::ACTION_REOPEN,Yii::$app->user->getId()); |
8 |
return true; |
9 |
} else { |
10 |
// over limit per meeting
|
11 |
return false; |
12 |
}
|
13 |
}
|
Ang withinActionLimit
ay pagsusuri sa
bilang ng pagkakataon na sinubukang buksan ng isang tao ang pagpupulong. Ang IncreaseSequence
ay para sa .ics na file—habang nagbabago ang petsa, oras at lugar ng
pagpupulong, ang ics na file ay kailangang masabihan.
Ang larawan sa ibaba ay nagpapakita ng pagpupulong na nakumpirma na mayroong iba’t ibang paunang mga pagpipilian na makikita:



Kapag pinindot ng gumagamit ang Make Changes sa menu sa itaas, ang kalagayan ng papupulong ay lilipat pabalik sa pagpaplano at maaari silang bumalik upang iupdate ang petsa, orast at lugar:



Paglilipat ng Oras ng Pagpupulong
Kapag ang mga pangyayari ay nagpangyari upang matanto ng mga kalahok na kailangan nilang magsimula miuli, ang Reschedule na pagpipilian ang mag-uurong sa kasalukuyang pagpupulong at lilikha ng imbitasyon sa bagong pagpaplano.
Sa kasalukuyan, hinihigpitan ko ang tampok
na ito sa mga taga-organisa (hindi sa mga kalahok), ngunit maaari koi tong
palawigin sa susunod. Ang Meeting.php::Reschedule()
na paraan ay sumusuporta
alinman sa taong gumagawa ng aksyon:
1 |
public function reschedule() { |
2 |
$newOwner = $user_id = Yii::$app->user->getId(); |
3 |
// user can only cancel their own Meeting
|
4 |
if ($this->owner_id == $user_id) { |
5 |
$addParticipant = false; |
6 |
$this->cancel($user_id); |
7 |
MeetingLog::add($this->id,MeetingLog::ACTION_RESCHEDULE,$user_id); |
8 |
} else { |
9 |
// if user is participant - needs to reverse
|
10 |
if (!isAttendee($this->id,$user_id)) { |
11 |
// user isn't owner or participant - error
|
12 |
return false; |
13 |
} else { |
14 |
// reverse the owner and participant
|
15 |
$addParticipant = $this->owner_id; |
16 |
}
|
17 |
}
|
18 |
// create new meeting - as copy of old meeting
|
19 |
$m = new Meeting(); |
20 |
$m->attributes = $this->attributes; |
21 |
$m->owner_id = $newOwner; |
22 |
$m->status = Meeting::STATUS_PLANNING; |
23 |
$m->created_at = time(); |
24 |
$m->updated_at = time(); |
25 |
$m->logged_at = 0; |
26 |
$m->cleared_at = 0; |
27 |
$m->sequence_id = 0; |
28 |
$m->save(); |
29 |
// clone the selected place (not all of them)
|
30 |
$chosenPlace = $this->getChosenPlace($this->id); |
31 |
if ($chosenPlace!==false) { |
32 |
$mp = new MeetingPlace; |
33 |
$mp->suggested_by = $newOwner; |
34 |
$mp->attributes = $chosenPlace->attributes; |
35 |
$mp->meeting_id = $m->id; |
36 |
$mp->created_at = time(); |
37 |
$mp->updated_at = time(); |
38 |
$mp->save(); |
39 |
}
|
40 |
// clone the participants
|
41 |
foreach ($this->participants as $p) { |
42 |
// skip if reschedule new owner was a participant
|
43 |
if ($p->participant_id==$user_id) { |
44 |
continue; |
45 |
}
|
46 |
// note Participant afterSave will create choices for place
|
47 |
$clone_p = new Participant(); |
48 |
$clone_p->attributes = $p->attributes; |
49 |
$clone_p->email = User::findOne($p->participant_id)->email; |
50 |
$clone_p->meeting_id = $m->id; |
51 |
$clone_p->invited_by = $newOwner; |
52 |
$clone_p->status = Participant::STATUS_DEFAULT; |
53 |
$clone_p->created_at = time(); |
54 |
$clone_p->updated_at = time(); |
55 |
$clone_p->save(); |
56 |
}
|
57 |
// if participant asked to reschedule - not yet allowed
|
58 |
if ($addParticipant!==false) { |
59 |
$newP = new Participant(); |
60 |
$newP->meeting_id = $m->id; |
61 |
$newP->participant_id = $addParticipant; |
62 |
$newP->invited_by = $user_id; |
63 |
$newP->status = Participant::STATUS_DEFAULT; |
64 |
$newP->created_at = time(); |
65 |
$newP->updated_at = time(); |
66 |
$newP->save(); |
67 |
}
|
68 |
return $m->id; |
69 |
}
|
Ang mga kalahot at ang napiling lugar ay makokopya sa bagong pagpupulong.
Pag-uulit ng Pagpupulong
Isa pang paraan sap ag-iiskedyul ay ang payagan ang mga kalahok na kopyahin ang mga nakaraang pagpupulong. Sa hinaharap, maaari kong hayaan ang tumitingin na magpasya kung sinong mga kalahok, mga lugar at mga oras ang kokopyahin, pero sa ngayon, ang Tagaplano ng Pagpupulong ang lumilikha ng bagong pagpupulong na may parehong mga kalahok at sa parehong lugar—at sa parehong araw ng linggo at oras ng unang araw at dalawang linggo sa hinaharap.
1 |
public function repeat() { |
2 |
// to do - expand repeat meeting to have more options
|
3 |
// e.g. pick same day and time in future week or two
|
4 |
// e.g. duplicate chosenplace or all places
|
5 |
// e.g. duplicate all participants or just some (complicated if participant duplicates)
|
6 |
$newOwner = $user_id = Yii::$app->user->getId(); |
7 |
// if user is participant - needs to reverse
|
8 |
if ($this->owner_id == $user_id) { |
9 |
$addParticipant = false; |
10 |
} else { |
11 |
if (!isAttendee($this->id,$user_id)) { |
12 |
// user isn't owner or participant - error
|
13 |
return false; |
14 |
} else { |
15 |
// reverse the owner and participant
|
16 |
$addParticipant = $this->owner_id; |
17 |
}
|
18 |
}
|
19 |
// create new meeting - as copy of old meeting
|
20 |
$m = new Meeting(); |
21 |
$m->attributes = $this->attributes; |
22 |
$m->owner_id = $newOwner; |
23 |
$m->status = Meeting::STATUS_PLANNING; |
24 |
$m->created_at = time(); |
25 |
$m->updated_at = time(); |
26 |
$m->logged_at = 0; |
27 |
$m->cleared_at = 0; |
28 |
$m->sequence_id = 0; |
29 |
$m->save(); |
30 |
// get prior meetings selected time and create two future times for the next two weeks
|
31 |
$chosenTime=$this->getChosenTime($this->id); |
32 |
$mt1 = MeetingTime::createTimePlus($m->id,$m->owner_id,$chosenTime->start,$chosenTime->duration); |
33 |
$mt2 = MeetingTime::createTimePlus($m->id,$m->owner_id,$mt1->start,$chosenTime->duration); |
34 |
// clone the selected place (not all of them)
|
35 |
$chosenPlace = $this->getChosenPlace($this->id); |
36 |
if ($chosenPlace!==false) { |
37 |
$mp = new MeetingPlace; |
38 |
$mp->suggested_by = $newOwner; |
39 |
$mp->attributes = $chosenPlace->attributes; |
40 |
$mp->meeting_id = $m->id; |
41 |
$mp->created_at = time(); |
42 |
$mp->updated_at = time(); |
43 |
$mp->save(); |
44 |
}
|
45 |
// clone the participants
|
46 |
foreach ($this->participants as $p) { |
47 |
// skip if reschedule new owner was a participant
|
48 |
if ($p->participant_id==$user_id) { |
49 |
continue; |
50 |
}
|
51 |
// note Participant afterSave will create choices for place
|
52 |
$clone_p = new Participant(); |
53 |
$clone_p->attributes = $p->attributes; |
54 |
$clone_p->email = User::findOne($p->participant_id)->email; |
55 |
$clone_p->meeting_id = $m->id; |
56 |
$clone_p->status = Participant::STATUS_DEFAULT; |
57 |
$clone_p->created_at = time(); |
58 |
$clone_p->updated_at = time(); |
59 |
$clone_p->save(); |
60 |
}
|
61 |
// if participant asked to repeat
|
62 |
// add the prior owner as a participant
|
63 |
if ($addParticipant!==false) { |
64 |
$newP = new Participant(); |
65 |
$newP->meeting_id = $m->id; |
66 |
$newP->participant_id = $addParticipant; |
67 |
$newP->invited_by = $user_id; |
68 |
$newP->status = Participant::STATUS_DEFAULT; |
69 |
$newP->created_at = time(); |
70 |
$newP->updated_at = time(); |
71 |
$newP->save(); |
72 |
}
|
73 |
MeetingLog::add($this->id,MeetingLog::ACTION_REPEAT,$user_id,0); |
74 |
return $m->id; |
75 |
}
|
MeetingTime::createTimePlus()
idinagdag sa ibaba ang Oras ng Pagpupulong sa parehong araw ng
linggo at oras ng araw, ngunit isang linggo sa hinaharap, kahit na ang orihinal
na pagpupulong ay naganap ilang buwan na ang nakalipas. Ang while
loop ay
kinakailangan para sa mga mas nauna pang mga pagpupulong.
1 |
public static function createTimePlus($meeting_id,$suggested_by,$start,$duration,$timeInFuture = 604800) { |
2 |
// finds time in multiples of a week or timeInFuture seconds ahead past the present time
|
3 |
$newStart = $start+$timeInFuture; |
4 |
while ($newStart<time()) { |
5 |
$newStart+=$timeInFuture; |
6 |
}
|
7 |
$mt = new MeetingTime(); |
8 |
$mt->meeting_id = $meeting_id; |
9 |
$mt->start = $newStart; |
10 |
$mt->duration = $duration; |
11 |
$mt->end = $mt->start+($mt->duration*3600); |
12 |
$mt->suggested_by = $suggested_by; |
13 |
$mt->status = MeetingTime::STATUS_SUGGESTED; |
14 |
$mt->updated_at = $mt->created_at = time(); |
15 |
$mt->save(); |
16 |
return $mt; |
17 |
}
|
Muling Pagpapadala ng mga Imbitasyon
Gumawa din ako ng muling pagpapadala na tampok kung sakaling ang kalahok ay hindi nakatanggap ng orihinal na imbitasyon o huling kumpirmasyon.
1 |
public static function resend($id) { |
2 |
$sender_id = Yii::$app->user->getId(); |
3 |
// check if within resend limit
|
4 |
$cnt = MeetingLog::find() |
5 |
->where(['actor_id'=>$sender_id]) |
6 |
->andWhere(['meeting_id'=>$id]) |
7 |
->andWhere(['action'=>MeetingLog::ACTION_RESEND]) |
8 |
->count(); |
9 |
if ($cnt >= Meeting::RESEND_LIMIT ) { |
10 |
return false; |
11 |
} else { |
12 |
$m = Meeting::findOne($id); |
13 |
if ($m->status == Meeting::STATUS_SENT) { |
14 |
$m->send($sender_id,true); |
15 |
// resend the planning invitation
|
16 |
} else if ($m->status == Meeting::STATUS_CONFIRMED) { |
17 |
// resend the confirmed invitation
|
18 |
$m->finalize($sender_id,true); |
19 |
}
|
20 |
MeetingLog::add($id,MeetingLog::ACTION_RESEND,$sender_id,0); |
21 |
return true; |
22 |
}
|
23 |
}
|
Balak kong muling gawin ang papalabas na email na pagpapaandar na gagana nang hindi kasabay at gagawing madali ang muling pagpapadala, ngunit sa kapalaran ang kasalukuyang mga paraan ay gumagana ng maayos sa eksena ng muling pagpapadala nang may kaunting mga pagbabago.
Kasaysayan ng Pagpupulong
Sa kabuuan ng serye, gumawa tayo ng tala ng bawat pagbabagong ginawa sa mga pagpupulong. Walang paraan upang makita ng mga dumalo ang kasaysayan ng pagpaplano. Ganito ang hitsura nito:



Ang MeetingLogController.php ang nagsusuri na ang tumitingin ay dumalo sa pagpupulong at gumagawa ng datos para sa tala ng pagtingin:
1 |
public function actionView($id) |
2 |
{
|
3 |
if (!Meeting::isAttendee($id,Yii::$app->user->getId())) { |
4 |
$this->redirect(['site/authfailure']); |
5 |
}
|
6 |
$timezone = MiscHelpers::fetchUserTimezone(Yii::$app->user->getId()); |
7 |
Yii::$app->timeZone = $timezone; |
8 |
$searchModel = new MeetingLogSearch(); |
9 |
$dataProvider = $searchModel->search(['MeetingLogSearch'=>['meeting_id'=>$id]]); |
10 |
$m= Meeting::findOne($id); |
11 |
return $this->render('index', [ |
12 |
'searchModel' => $searchModel, |
13 |
'dataProvider' => $dataProvider, |
14 |
'meeting_id' => $id, |
15 |
'subject' => $m->getMeetingHeader('log'), |
16 |
'timezone' => $timezone, |
17 |
]);
|
18 |
}
|
Tapos ang /frontend/views/meeting-log/index.php ang gumagawa ng mga datos na ipinapakita sa itaas:
1 |
<?php Pjax::begin(); ?> |
2 |
<div class="meeting-log-index"> |
3 |
<h1><?php echo Html::encode($this->title) ?></h1> |
4 |
|
5 |
<?php echo GridView::widget([ |
6 |
'dataProvider' => $dataProvider, |
7 |
//'filterModel' => $searchModel,
|
8 |
'columns' => [ |
9 |
[
|
10 |
'label'=>'Actor', |
11 |
'attribute' => 'actor_id', |
12 |
'format' => 'raw', |
13 |
'value' => function ($model) { |
14 |
return '<div>'.MiscHelpers::getDisplayName($model->actor_id).'</div>'; |
15 |
},
|
16 |
],
|
17 |
[
|
18 |
'label'=>'Action', |
19 |
'attribute' => 'action', |
20 |
'format' => 'raw', |
21 |
'value' => function ($model) { |
22 |
return '<div>'.$model->getMeetingLogCommand().'</div>'; |
23 |
},
|
24 |
],
|
25 |
[
|
26 |
'label'=>'Item', |
27 |
'attribute' => 'item_id', |
28 |
'format' => 'raw', |
29 |
'value' => function ($model) { |
30 |
return '<div>'.$model->getMeetingLogItem().'</div>'; |
31 |
},
|
32 |
],
|
33 |
[
|
34 |
'label'=>'Created', |
35 |
'attribute' => 'created_at', |
36 |
'format' => 'raw', |
37 |
'value' => function ($model) { |
38 |
return '<div>'.Yii::$app->formatter->asDatetime($model->created_at,"hh:ss MMM d").'</div>'; |
39 |
},
|
40 |
],
|
41 |
],
|
42 |
]);
|
43 |
?>
|
44 |
<?= Html::a(Yii::t('frontend', 'Return to Meeting'), ['meeting/view', 'id' => $meeting_id], |
45 |
['class' => 'btn btn-primary btn-info', |
46 |
'title'=>Yii::t('frontend','Return to meeting page'), |
47 |
]); ?> |
48 |
<?php Pjax::end(); ?> |
Anong Kasunod?
Ngayon ay nasa matinding code sprint ako upang makupleto ang paglabas ng beta. Ang mga diyos ng editorial sa Envato Tuts+ ay sinikap ang kanilang pinakamahusay upang abalahin ako sa pamamagitan ng mga robot na nagkokontrol sa isip at parang OKCupid na mga tunog mula sa kanilang mga daloy ng trabaho na aplikasyon na pinagana ng Ios, ngunit nabigo sila. Ang Tagaplano ng Pagpupulong ay patuloy na umuunlad sa mabilis na lakad.
Ang paglutas ng pakikipagkapwang pag-iininyero at UX para sa mga dadalo ng pagpupulong na hihiling at tutugon sa mas maliliit na pag-aayos sap ag-iiskedyul ay maaaring makabuo o makasira ng tatak ng Tagaplano ng Pagpupulong, at iyan kung ano ang pinakapinagtatrabahuhan ko.
Kung hindi pa kayo, halina iiskedyul na ang inyong unang pagpupulong sa pamamagitan ng Tagaplano ng Pagpupulong. Balak ko din magsulat ng tutoryal tungkol sa pagpopondo sa karamihan ng tao, kaya pakisaalang-alang ang sumusunod na WeFunder na Tagaplano ng Pagpupulong Planner na pahina. Maaari din kayong lumapit sa akin @reifman. Lagi akong bukas sa mga bagong ideya ng tampok at mga mungkahing paksa para sa mga tutoryal sa hinaharap.
Manatiling nakatutok para sa lahat ng ito at marami pang darating ng mga tutoryal sa pamamagitan ng pagtingin sa Paggawa ng Inyong Panimula na may PHP na serye.