diff --git a/app/FlutterFileresult.php b/app/FlutterFileresult.php new file mode 100644 index 0000000..7700fbe --- /dev/null +++ b/app/FlutterFileresult.php @@ -0,0 +1,11 @@ +roleid == 'student') { + $check = \App\User::find(Auth::user()->id); + if ($check->status != 'active') return view('student/fluttercourse/home')->with(['status' => $check->status]); + } + + $stagelist = \App\ExerciseTopic::orderBy('stage', 'asc')->get(); + $topiclist = \App\ExerciseTopic::orderBy('name', 'asc')->get(); + + if ($topiclist->count() > 0) { + $itemsstage = \App\ExerciseTopic::orderBy('stage', 'asc') + ->selectRaw('stage, min(id) as id') + ->groupBy('stage') + ->pluck('stage', 'id'); + + // $filter = $request->input('topicList', $topiclist[0]['id']); + + $filter = $request->input('stageList', $topiclist[0]['id']); + + $option = $request->input('option', 'github'); + + $stage = \App\ExerciseTopic::where('exercises.id', '=', $filter) + ->select( + 'exercises.id', + 'exercises.stage' + ) + ->get(); + + $topic = \App\ExerciseTopic::where('exercises.stage', '=', $stage[0]['stage']) + ->select( + 'exercises.id', + 'exercises.name', + 'exercises.desc', + 'exercise_files.guide', + 'exercise_files.testfile', + 'exercise_files.supplement', + 'exercise_files.other' + ) + ->leftJoin('exercise_files', 'exercise_files.exercise', '=', 'exercises.id') + ->get(); + return view('student/fluttercourse/exercise/index') + ->with(compact('itemsstage')) + ->with(compact('filter')) + ->with(compact('topic')) + // ->with(compact('result')) + ->with(compact('option')); + } else { + return view('student/fluttercourse/exercise/index'); + } + } + + private function validateUrl($url) + { + $path = parse_url($url, PHP_URL_PATH); + $encoded_path = array_map('urlencode', explode('/', $path)); + $url = str_replace($path, implode('/', $encoded_path), $url); + + if (filter_var($url, FILTER_VALIDATE_URL)) { + $result = parse_url($url); + if (($result['scheme'] == 'https') && ($this->endsWith($result['host'], 'github.com'))) { + return true; + } else { + return false; + } + } else { + return false; + } + } + + private function validateZipFile(Request $request) + { + $rules = [ + 'zipfile' => 'required', + 'comment' => 'required', + 'duration' => 'required', + ]; + + $msg = [ + 'zipfile.required' => 'Zip file must not empty', + 'comment.required' => 'Exercise comment must not empty', + 'duration.required' => 'Duration time must not empty', + ]; + + $validator = Validator::make($request->all(), $rules, $msg); + + if ($validator->fails()) { + return Redirect::to('student/fluttercourse/exercise?topicList=' . $request->get('exercise')) + ->withErrors($validator); + } else { + $userid = Auth::user()->id; + $exercise = $request->get('exercise'); + $file = $request->file('zipfile'); + $filename = $file->getClientOriginalName(); + // + //$file = $request->file('zipfile'); + if ($filename != '') { + //$array = explode('.', $path); + //$ext = strtolower(end($array)); + $ext = strtolower(pathinfo($filename, PATHINFO_EXTENSION)); + if ($ext == "zip") { + $zipFile = $file->store('exercise_results', 'public'); + + if ($zipFile != '') { + $entity = new \App\ExerciseSubmit(); + + $entity->userid = $userid; + $entity->exercise = $exercise; + $entity->validstat = "valid"; + $entity->checkresult = "waiting"; + $entity->projectfile = $zipFile; + $entity->comment = $request->get('comment'); + $entity->duration = $request->get('duration'); + + $entity->save(); + + $data = \App\ExerciseTopic::find($exercise); + Session::flash('message', $data['name'] . ' Validation by Uploading Zip Project is Success'); + } else { + Session::flash('message', 'Storing file ' . $request->file('zipfile') . ' was FAILED'); + } + } else { + Session::flash('message', 'File extension is not zip -> ' . $filename . ' is wrong .' . $ext); + } + } else { + Session::flash('message', 'Zip File is empty'); + } + + + //return "Add new topic is success"; + return Redirect::to('student/fluttercourse/exercise?topicList=' . $exercise); + } + } + + private function validateGithubLink(Request $request) + { + $rules = [ + 'githublink' => 'required', + 'comment' => 'required', + 'duration' => 'required', + ]; + + $msg = [ + 'githublink.required' => 'Github link must not empty', + 'comment.required' => 'Exercise comment must not empty', + 'duration.required' => 'Duration time must not empty', + ]; + + $validator = Validator::make($request->all(), $rules, $msg); + + if ($validator->fails()) { + return Redirect::to('student/fluttercourse/exercise?topicList=' . $request->get('exercise')) + ->withErrors($validator); + } else { + $userid = Auth::user()->id; + $exercise = $request->get('exercise'); + $link = $request->get('githublink'); + // + $trimmedlink = trim($link); + if ($this->validateUrl($trimmedlink)) { + $entity = new \App\ExerciseSubmit; + + $entity->userid = $userid; + $entity->exercise = $exercise; + $entity->validstat = "valid"; + $entity->checkresult = "waiting"; + $entity->validator = ""; + $entity->comment = $request->get('comment');; + $entity->duration = $request->get('duration');; + $entity->githublink = $trimmedlink; + + $entity->save(); + + $data = \App\ExerciseTopic::find($exercise); + Session::flash('message', $data['name'] . ' Validation by submitting GitHub link is Success'); + + //Session::flash('message','URL valid '.$link); + + } else { + Session::flash('message', 'URL is not VALID ' . $link); + } + + //return "Add new topic is success"; + return Redirect::to('student/fluttercourse/exercise?topicList=' . $exercise); + } + } + + private function endsWith($haystack, $needle) + { + return substr_compare($haystack, $needle, -strlen($needle)) === 0; + } + + /** + * Store a newly created resource in storage. + * + * @return Response + */ + public function store(Request $request) + { + if (($request->get('action') == 'validate') && (strlen($request->submitbutton) > 5)) { + if ($request->get('option') == 'zipfile') { + return $this->validateZipFile($request); + } else if ($request->get('option') == 'github') { + return $this->validateGithubLink($request); + } else { + return Redirect::to('student/fluttercourse/exercise?topicList=' . $request->get('exercise') . '&option=' . $request->get('option') . + '&submit=' . $request->submitbutton); + } + } else { //clicking radio button + return Redirect::to('student/fluttercourse/exercise?topicList=' . $request->get('exercise') . '&option=' . $request->get('option')); + //'&submit='.$request->submitbutton); + } + } +} + diff --git a/app/Http/Controllers/FlutterExerciseStdValidController.php b/app/Http/Controllers/FlutterExerciseStdValidController.php new file mode 100644 index 0000000..d665b52 --- /dev/null +++ b/app/Http/Controllers/FlutterExerciseStdValidController.php @@ -0,0 +1,57 @@ +roleid == 'student') { + $check = \App\User::find(Auth::user()->id); + if ($check->status != 'active') return view('student/fluttercourse/home')->with(['status' => $check->status]); + } + + $entities = \App\ExerciseSubmit::where('exercise_submits.userid', Auth::user()->id) + ->select( + 'exercise_submits.id', + 'exercises.name', + 'exercise_submits.checkstat', + 'exercise_validations.report', + 'exercise_submits.duration' + ) + ->leftJoin('exercise_validations', 'exercise_validations.exercisesubmitid', '=', 'exercise_submits.id') + ->leftJoin('exercises', 'exercise_submits.exercise', '=', 'exercises.id') + ->get(); + + return view('student/fluttercourse/exercisevalid/index') + ->with(compact('entities')); + } + + public function show($id) + { + $entities = \App\ExerciseSubmit::where('exercise_submits.userid', Auth::user()->id) + ->where('exercise_submits.id', $id) + ->select( + 'exercise_submits.id', + 'exercises.name', + 'exercises.singletestcode', + 'exercise_submits.checkstat', + 'exercise_validations.report', + 'exercise_validations.duration', + 'exercise_validations.created_at' + ) + ->leftJoin('exercise_validations', 'exercise_validations.exercisesubmitid', '=', 'exercise_submits.id') + ->leftJoin('exercises', 'exercise_submits.exercise', '=', 'exercises.id') + ->get(); + + $student = \App\User::find(Auth::user()->id); + + return view('student/fluttercourse/exercisevalid/show') + ->with(compact('entities')) + ->with(compact('student')); + } +} + diff --git a/app/Http/Controllers/FlutterExerciseSubmissionController.php b/app/Http/Controllers/FlutterExerciseSubmissionController.php new file mode 100644 index 0000000..3630ca2 --- /dev/null +++ b/app/Http/Controllers/FlutterExerciseSubmissionController.php @@ -0,0 +1,269 @@ +roleid == 'student') { + $check = \App\User::find(Auth::user()->id); + if ($check->status != 'active') return view('student/fluttercourse/home')->with(['status' => $check->status]); + } + $stagelist = \App\ExerciseTopic::orderBy('stage', 'asc')->get(); + $exerciselist = \App\ExerciseTopic::orderBy('name', 'asc')->get(); + + if ($exerciselist->count() > 0) { + + // daftar stage untuk dropdown menu + $itemsstage = \App\ExerciseTopic::orderBy('stage', 'asc') + ->selectRaw('stage, min(id) as id') + ->groupBy('stage') + ->pluck('stage', 'id'); + + // id stageList dari url + $filter = $request->input('stageList', $stagelist[0]['id']); + + // id exerciseList dari url + $filterexercise = $request->input('exerciseList', $exerciselist[0]['id']); + + // get nama stage dari $filter + $stagename = \App\ExerciseTopic::orderBy('stage', 'asc') + ->where('id', $filter) + ->pluck('stage'); + + // daftar exercise untuk dropdown menu + $itemsexercise = \App\ExerciseTopic::orderBy('id', 'asc') + ->where('stage', $stagename) + ->pluck('name', 'id'); + + if (!($this->checkstage($filter, $filterexercise))) { + return Redirect::to('student/fluttercourse/exercisesubmission?stageList=' . $filter . '&exerciseList=' . $filter); + } + + $completed = \App\ExerciseSubmit::where('userid', '=', Auth::user()->id) + ->where('exercise', '=', $filterexercise) + ->get()->count(); + + $option = $request->input('option', 'github'); + + $stage = \App\ExerciseTopic::where('exercises.id', '=', $filter) + ->select( + 'exercises.id', + 'exercises.stage' + ) + ->get(); + + $topic = \App\ExerciseTopic::where('exercises.stage', '=', $stage[0]['stage']) + ->select( + 'exercises.name' + ) + ->get(); + + $result = \App\ExerciseValidation::where('exercise_validations.userid', Auth::user()->id) + ->where('exercise_submits.exercise', $filter) + ->select( + 'exercise_submits.checkstat', + 'exercise_submits.checkresult' + ) + ->leftJoin('exercise_submits', 'exercise_validations.exercisesubmitid', '=', 'exercise_submits.id') + ->first(); + + return view('student/fluttercourse/exercisesubmission/index') + ->with(compact('itemsstage')) + ->with(compact('itemsexercise')) + ->with(compact('filter')) + ->with(compact('filterexercise')) + ->with(compact('topic')) + ->with(compact('completed')) + ->with(compact('result')) + ->with(compact('option')); + } else { + return view('student/fluttercourse/exercisesubmission/index'); + } + } + + private function checkstage($stage, $exercise) + { + $stagename = \App\ExerciseTopic::orderBy('stage', 'asc') + ->where('id', $stage) + ->pluck('stage'); + $exercisestage = \App\ExerciseTopic::orderBy('stage', 'asc') + ->where('id', $exercise) + ->pluck('stage'); + + if ($stagename == $exercisestage) { + return true; + } else { + return false; + } + } + + private function validateUrl($url) + { + $path = parse_url($url, PHP_URL_PATH); + $encoded_path = array_map('urlencode', explode('/', $path)); + $url = str_replace($path, implode('/', $encoded_path), $url); + + if (filter_var($url, FILTER_VALIDATE_URL)) { + $result = parse_url($url); + if (($result['scheme'] == 'https') && ($this->endsWith($result['host'], 'github.com'))) { + return true; + } else { + return false; + } + } else { + return false; + } + } + + private function validateZipFile(Request $request) + { + $rules = [ + 'zipfile' => 'required', + 'comment' => 'required', + 'duration' => 'required', + ]; + + $msg = [ + 'zipfile.required' => 'Zip file must not empty', + 'comment.required' => 'Exercise comment must not empty', + 'duration.required' => 'Duration time must not empty', + ]; + + $validator = Validator::make($request->all(), $rules, $msg); + + if ($validator->fails()) { + return Redirect::to('student/fluttercourse/exercisesubmission?stageList=' . $request->get('stage') . '&exerciseList=' . $request->get('exercise')) + ->withErrors($validator); + } else { + $userid = Auth::user()->id; + $exercise = $request->get('exercise'); + $file = $request->file('zipfile'); + $filename = $file->getClientOriginalName(); + // + //$file = $request->file('zipfile'); + if ($filename != '') { + //$array = explode('.', $path); + //$ext = strtolower(end($array)); + $ext = strtolower(pathinfo($filename, PATHINFO_EXTENSION)); + if ($ext == "zip") { + $zipFile = $file->store('exercise_results', 'public'); + + if ($zipFile != '') { + $entity = new \App\ExerciseSubmit(); + + $entity->userid = $userid; + $entity->exercise = $exercise; + $entity->validstat = "valid"; + $entity->checkresult = "waiting"; + $entity->projectfile = $zipFile; + $entity->comment = $request->get('comment'); + $entity->duration = $request->get('duration'); + + $entity->save(); + + $data = \App\ExerciseTopic::find($exercise); + Session::flash('message', $data['name'] . ' Validation by Uploading Zip Project is Success'); + } else { + Session::flash('message', 'Storing file ' . $request->file('zipfile') . ' was FAILED'); + } + } else { + Session::flash('message', 'File extension is not zip -> ' . $filename . ' is wrong .' . $ext); + } + } else { + Session::flash('message', 'Zip File is empty'); + } + + + //return "Add new topic is success"; + return Redirect::to('student/fluttercourse/exercisesubmission?stageList=' . $request->get('stage') . '&exerciseList=' . $request->get('exercise')); + } + } + + private function validateGithubLink(Request $request) + { + $rules = [ + 'githublink' => 'required', + 'comment' => 'required', + 'duration' => 'required', + ]; + + $msg = [ + 'githublink.required' => 'Github link must not empty', + 'comment.required' => 'Exercise comment must not empty', + 'duration.required' => 'Duration time must not empty', + ]; + + $validator = Validator::make($request->all(), $rules, $msg); + + if ($validator->fails()) { + return Redirect::to('student/fluttercourse/exercisesubmission?stageList=' . $request->get('stage') . '&exerciseList=' . $request->get('exercise')) + ->withErrors($validator); + } else { + $userid = Auth::user()->id; + $exercise = $request->get('exercise'); + $link = $request->get('githublink'); + // + $trimmedlink = trim($link); + if ($this->validateUrl($trimmedlink)) { + $entity = new \App\ExerciseSubmit; + + $entity->userid = $userid; + $entity->exercise = $exercise; + $entity->validstat = "valid"; + $entity->checkresult = "waiting"; + $entity->comment = $request->get('comment');; + $entity->duration = $request->get('duration');; + $entity->githublink = $trimmedlink; + + $entity->save(); + + $data = \App\ExerciseTopic::find($exercise); + Session::flash('message', $data['name'] . ' Validation by submitting GitHub link is Success'); + + //Session::flash('message','URL valid '.$link); + + } else { + Session::flash('message', 'URL is not VALID ' . $link); + } + + //return "Add new topic is success"; + return Redirect::to('student/fluttercourse/exercisesubmission?stageList=' . $request->get('stage') . '&exerciseList=' . $request->get('exercise')); + } + } + + private function endsWith($haystack, $needle) + { + return substr_compare($haystack, $needle, -strlen($needle)) === 0; + } + + /** + * Store a newly created resource in storage. + * + * @return Response + */ + public function store(Request $request) + { + if (($request->get('action') == 'validate') && (strlen($request->submitbutton) > 5)) { + if ($request->get('option') == 'zipfile') { + return $this->validateZipFile($request); + } else if ($request->get('option') == 'github') { + return $this->validateGithubLink($request); + } else { + return Redirect::to('student/fluttercourse/exercisesubmission'); + } + } else { //clicking radio button + return Redirect::to('student/fluttercourse/exercisesubmission?stageList=' . $request->get('stage') . '&exerciseList=' . $request->get('exercise') . '&option=' . $request->get('option')); + //'&submit='.$request->submitbutton); + } + } +} + diff --git a/app/Http/Controllers/FlutterExerciseValidController.php b/app/Http/Controllers/FlutterExerciseValidController.php new file mode 100644 index 0000000..391117f --- /dev/null +++ b/app/Http/Controllers/FlutterExerciseValidController.php @@ -0,0 +1,180 @@ +join('user_submits', 'user_submits.userid', '=', 'users.id') + ->join('class_members', 'class_members.student', '=', 'users.id') + ->join('classrooms', 'classrooms.id', '=', 'class_members.classid') + ->join('users as x', 'x.id', '=', 'users.uplink') + ->select('users.id', 'users.name', 'users.email', 'users.roleid', 'classrooms.name as classname', 'x.name as teacher') + ->orderBy('users.uplink', 'asc') + ->orderBy('class_members.classid', 'asc') + ->orderBy('users.name', 'asc') + ->get(); + } + + private function getListStudentAll() + { + return \App\User::where('users.status', '=', 'active') + + ->join('user_submits', 'user_submits.userid', '=', 'users.id') + ->join('class_members', 'class_members.student', '=', 'users.id') + ->join('classrooms', 'classrooms.id', '=', 'class_members.classid') + ->join('users as x', 'x.id', '=', 'users.uplink') + ->select('users.id', 'users.name', 'users.email', 'users.roleid', 'classrooms.name as classname', 'x.name as teacher') + ->orderBy('users.uplink', 'asc') + ->orderBy('class_members.classid', 'asc') + ->orderBy('users.name', 'asc') + ->get(); + } + + public function index(Request $request) + { + if (Auth::user()->roleid == 'admin') { + $student = $this->getListStudentAll(); + $filter = $request->input('stdList', ($student->count() > 0) ? $student[0]['id'] : ''); + } else if (Auth::user()->roleid == 'teacher') { + $student = $this->getListStudent(Auth::user()->id); + $filter = $request->input('stdList', ($student->count() > 0) ? $student[0]['id'] : ''); + } else { //student + $check = \App\User::find(Auth::user()->id); + if ($check->status != 'active') return view('student/home')->with(['status' => $check->status]); + $filter = Auth::user()->id; + } + + $entities = \App\StudentSubmit::where('student_submits.userid', '=', $filter) + ->select( + 'topics.id', + 'topics.name', + 'task_results_group_student.passed', + 'task_results_group_student.failed', + 'task_results_group_student.avg_duration', + 'task_results_group_student.tot_duration', + 'student_submits.checkstat', + 'student_submits.checkresult', + 'student_validations_pertopic.failed as vfailed', + 'student_validations_pertopic.passed as vpassed' + ) + ->leftJoin( + 'task_results_group_student', + function ($join) { + $join->on('task_results_group_student.userid', '=', 'student_submits.userid'); + $join->on('task_results_group_student.topic', '=', 'student_submits.topic'); + } + ) + ->leftJoin( + 'student_validations_pertopic', + function ($join2) { + $join2->on('student_validations_pertopic.userid', '=', 'student_submits.userid'); + $join2->on('student_validations_pertopic.topic', '=', 'student_submits.topic'); + } + ) + ->join('topics', 'topics.id', '=', 'student_submits.topic') + ->orderBy('topics.name', 'asc') + ->get(); + + + + if (Auth::user()->roleid == 'admin') { + $data = ['entities' => $entities, 'items' => $student, 'filter' => $filter]; + return view('admin/studentres/index')->with($data); + } else if (Auth::user()->roleid == 'teacher') { + $data = ['entities' => $entities, 'items' => $student, 'filter' => $filter]; + return view('teacher/studentres/index')->with($data); + } else { //as student + $data = ['entities' => $entities]; + return view('student/valid/index')->with($data); + } + } + + private function getDataShow($student, $id) + { + $entities = \App\ExerciseStudentResultView::where('userid', $student) + ->where('id', $id) + ->get(); + $exercise = \App\ExerciseTopic::find($entities[0]['exerciseid']); + $user = \App\User::find($student); + $data = ['entities' => $entities, 'exercise' => $exercise, 'student' => $user]; + + // dd($uitestfile); + return $data; + } + + public function show($id) + { + $data = $this->getDataShow(Auth::user()->id, $id); + + return view('student/uistudentres/show')->with($data); + } + + public function showadmin($student, $id) + { + // + $data = $this->getDataShow($student, $id); + if (Auth::user()->roleid == 'admin') { + //$data=['entities'=>$entities, 'items'=>$student, 'filter'=>$filter]; + return view('admin/exercisestudentres/show')->with($data); + } else if (Auth::user()->roleid == 'teacher') { + //$data=['entities'=>$entities, 'items'=>$student, 'filter'=>$filter]; + return view('teacher/uistudentres/show')->with($data); + } else { //as student + //$data=['entities'=>$entities]; + return view('student/uistudentres/show')->with($data); + } + //return view('teacher/studentres/show')->with($data); + } + + + + private function getFileSource($student, $topicid, $id) + { + $entities = \App\ExerciseFilesResult::where('exercise_file_results.userid', '=', $student) + ->select('exercise_file_results.rscfile', 'exercise_topic_files.filename') + ->join( + 'exercise_topic_files', + function ($join) { + $join->on('exercise_file_results.fileid', '=', 'exercise_topic_files.id'); + } + ) + ->where('exercise_topic_files.exercise', $topicid) + ->orderBy('exercise_topic_files.id', 'asc') + ->get(); + + $topic = \App\ExerciseTopic::find($topicid); + $user = \App\User::find($student); + $data = ['entities' => $entities, 'topic' => $topic, 'student' => $user]; + + return $data; + } + + + public function showsource($student, $topicid, $id) + { + // + $data = $this->getFileSource($student, $topicid, $id); + + if (Auth::user()->roleid == 'admin') { + //$data=['entities'=>$entities, 'items'=>$student, 'filter'=>$filter]; + return view('admin/exerciseuploadsrc/index')->with($data); + } else if (Auth::user()->roleid == 'teacher') { + //$data=['entities'=>$entities, 'items'=>$student, 'filter'=>$filter]; + return view('teacher/uploadsrc/index')->with($data); + } else { //as student + //$data=['entities'=>$entities]; + return view('student/uiuploadsrc/index')->with($data); + } + //return view('teacher/studentres/show')->with($data); + } +} + diff --git a/resources/views/student/fluttercourse/exercise/index.blade.php b/resources/views/student/fluttercourse/exercise/index.blade.php new file mode 100644 index 0000000..21053e1 --- /dev/null +++ b/resources/views/student/fluttercourse/exercise/index.blade.php @@ -0,0 +1,101 @@ +@extends('student/fluttercourse/home') +@section('content') +
| + | Guide Documents | +Test Files | +Supplement Files | +Other Files | +
|---|---|---|---|---|
| Resource for {{ $data['name'] }} | ++ {{ $data['desc'] }} + | +
+ @if($data['guide'] !='')
+
+ Download
+
+ @else
+ Empty
+ @endif
+ |
+
+ @if($data['testfile'] !='')
+
+ Download
+
+ @else
+ Empty
+ @endif
+ |
+
+ @if($data['supplement'] !='')
+
+ Download
+
+ @else
+ Empty
+ @endif
+ |
+
+ @if($data['other'] !='')
+
+ Download
+
+ @else
+ Empty
+ @endif
+ |
+
+ @endforeach
+
+
| Exercise Name | +Validation Detail | +Status | +
|---|---|---|
| {{ $entity['name'] }} | +{{ $entity['checkstat'] }} | +{{ $entity['checkresult'] }} | +
| No validation data yet | +||
The link must be PUBLIC access. Format : https://github.com/{{ '
| Exercise Name | +Duration | +Validation Detail | +Status | +Action | +|
|---|---|---|---|---|---|
| {{ $entity['name'] }} | +Total: {{ $entity['duration'] }} minute(s) | +{!! nl2br($entity['report']) !!} | +{{ $entity['checkstat'] }} | +
+
+ Show Detail
+
+ |
+
+ |
| No validation data yet | +|||||
| No. | +Test File | +Exercise Name | +Result | +Report | +Exec Time | +Duration | +
|---|---|---|---|---|---|---|
| {{ $index+1 }} | +{{ $entity['singletestcode'] }} | +{{ $entity['name'] }} | +{{ $entity['checkstat'] }} | +{!! nl2br(e($entity['report'])) !!} | +{{ $entity['created_at'] }} | +{{ $entity['duration'] }} seconds | +
| Task No. | -Description | -Topic Name | -Show | -
|---|---|---|---|
| 1 | -Firebase Configuration | -- C3:Java - Firebase Java Edition - | -- - | -
| 2 | -Create Register Activity | -- C3:Java - Firebase Java Edition - | -- - | -
| 3 | -Create Login Activity | -- C3:Java - CFirebase Java Edition - | -- - | -
| 4 | -Desain UI Seller Home and develope Seller Home Activity | -- C3:Java - Firebase Java Edition - | -- - | -
| 5 | -Desain UI Seller Home AddProduct and Develope Seller Home | -- C3:Java - Firebase Java Edition - | -- - | -
| 6 | -Desain UI Seller Home Detail Product dan Develop Seller Home Detail Product Activity | -- C3:Java - Firebase Java Edition - | -- - | -
| 7 | -Desain UI Buyer Home dan Develop Buyer Home Activity | -- C3:Java - Firebase Java Edition - | -- - | -
| 8 | -Desain UI Buyer Home Detail Productdan Develop Buyer Home Detail ProductActivity | -- C3:Java - Firebase Java Edition - | -- - | -
| 9 | -Desain UI Cart dan Develop Cart Activity | -- C3:Java - Firebase Java Edition - | -- - | -
| 10 | -Desain UI Detail Cart dan Develop Detail Cart Activity | -- C3:Java - Firebase Java Edition - | -- - | -