diff --git a/app/Text/JsonTextRepository.php b/app/Text/JsonTextRepository.php new file mode 100644 index 0000000..fc8640d --- /dev/null +++ b/app/Text/JsonTextRepository.php @@ -0,0 +1,108 @@ +filePath = __DIR__.'/../../data/texts.json'; + } + + public function create(CreateTextDto $dto): Text + { + $texts = $this->readTexts(); + $id = $this->getNextId($texts); + + $text = new Text(id: $id, name: $dto->name); + $texts[] = ['id' => $id, 'name' => $dto->name]; + + $this->writeTexts($texts); + + return $text; + } + + public function find(int $id): ?Text + { + $texts = $this->readTexts(); + + foreach ($texts as $data) { + if ($data['id'] === $id) { + return new Text( + id: $data['id'], + name: $data['name'], + ); + } + } + + return null; + } + + /** + * @return Text[] + */ + public function getAll(): array + { + $texts = $this->readTexts(); + + return array_map( + function (array $data) { + return new Text( + id: $data['id'], + name: $data['name'], + ); + }, + $texts + ); + } + + /** + * @return array + */ + private function readTexts(): array + { + if (!file_exists($this->filePath)) { + return []; + } + + $content = file_get_contents($this->filePath); + + return json_decode($content, true) ?? []; + } + + /** + * @param array $texts + */ + private function writeTexts(array $texts): void + { + file_put_contents( + $this->filePath, + json_encode($texts, JSON_PRETTY_PRINT) + ); + } + + /** + * @param array $texts + */ + private function getNextId(array $texts): int + { + if (empty($texts)) { + return 1; + } + + $maxId = 0; + foreach ($texts as $text) { + if ($text['id'] > $maxId) { + $maxId = $text['id']; + } + } + + return $maxId + 1; + } +} diff --git a/app/Text/TextRepository.php b/app/Text/TextRepository.php index a280407..d899bcf 100644 --- a/app/Text/TextRepository.php +++ b/app/Text/TextRepository.php @@ -10,4 +10,9 @@ interface TextRepository public function create(CreateTextDto $dto): Text; public function find(int $id): ?Text; + + /** + * @return Text[] + */ + public function getAll(): array; } diff --git a/app/View/ViewController.php b/app/View/ViewController.php index fb46073..a9f4ccc 100644 --- a/app/View/ViewController.php +++ b/app/View/ViewController.php @@ -2,10 +2,15 @@ namespace App\View; +use App\Text\TextRepository; use Psr\Http\Message\ResponseInterface as Response; class ViewController { + public function __construct( + private TextRepository $textRepository, + ) {} + public function admin(Response $response): Response { $html = file_get_contents(__DIR__.'/../../views/templates/admin.php', true); @@ -13,4 +18,20 @@ class ViewController return $response; } + + public function texts(Response $response): Response + { + $texts = $this->textRepository->getAll(); + + $textsList = ''; + foreach ($texts as $text) { + $textsList .= '
  • ' . htmlspecialchars($text->getName()) . '
  • '; + } + + $html = file_get_contents(__DIR__.'/../../views/templates/texts.php', true); + $html = str_replace('{{texts}}', $textsList, $html); + $response->getBody()->write($html); + + return $response; + } } diff --git a/bootstrap/app.php b/bootstrap/app.php index 1fc3b7e..5d081cd 100644 --- a/bootstrap/app.php +++ b/bootstrap/app.php @@ -12,5 +12,6 @@ $app = Bridge::create($container); $app->addErrorMiddleware(true, true, true); $app->get('/admin', [ViewController::class, 'admin']); +$app->get('/admin/texts', [ViewController::class, 'texts']); return $app; diff --git a/bootstrap/container.php b/bootstrap/container.php index 3a35c97..09a0d9a 100644 --- a/bootstrap/container.php +++ b/bootstrap/container.php @@ -1,9 +1,12 @@ DI\create(JsonTextRepository::class), ]); return $container; diff --git a/cypress/e2e/admin.cy.js b/cypress/e2e/admin.cy.js index c277eb9..c06aece 100644 --- a/cypress/e2e/admin.cy.js +++ b/cypress/e2e/admin.cy.js @@ -1,7 +1,24 @@ describe('The admin page', () => { - it('successfully loads texts', () => { - cy.visit('/admin') - cy.get('#newTextname').type('new text') - cy.get('#submit').click() + beforeEach(() => { + cy.visit('/admin') + }) + + it('navigates to texts page', () => { + cy.get('#texts').click() + cy.url().should('include', '/admin/texts') + }) + + it('shows texts page with heading and form', () => { + cy.visit('/admin/texts') + cy.get('h1').should('contain', 'Texts') + cy.get('#newTextName').should('exist') + cy.get('#submit').should('exist') + }) + + it('creates a new text', () => { + cy.visit('/admin/texts') + cy.get('#newTextName').type('Test Text') + cy.get('#submit').click() + cy.contains('Test Text') }) }) diff --git a/data/texts.json b/data/texts.json new file mode 100644 index 0000000..fe51488 --- /dev/null +++ b/data/texts.json @@ -0,0 +1 @@ +[] diff --git a/tests/Fakes/FakeTextRepository.php b/tests/Fakes/FakeTextRepository.php index 86d3076..388e01c 100644 --- a/tests/Fakes/FakeTextRepository.php +++ b/tests/Fakes/FakeTextRepository.php @@ -47,4 +47,20 @@ class FakeTextRepository implements TextRepository { return count($this->existingTexts); } + + /** + * @return Text[] + */ + public function getAll(): array + { + return array_map( + function (Text $text) { + return new Text( + id: $text->getId(), + name: $text->getName(), + ); + }, + $this->existingTexts + ); + } } diff --git a/views/templates/admin.php b/views/templates/admin.php index c027843..7f463d4 100644 --- a/views/templates/admin.php +++ b/views/templates/admin.php @@ -1,10 +1,9 @@ - Daily Goals + Daily Goals - Admin - - + Texts diff --git a/views/templates/texts.php b/views/templates/texts.php new file mode 100644 index 0000000..b5058ab --- /dev/null +++ b/views/templates/texts.php @@ -0,0 +1,15 @@ + + + + Daily Goals - Texts + + +

    Texts

    + Back to Admin + + + + +