From f2f7e4e86391739af698d495bb48d72019ac7921 Mon Sep 17 00:00:00 2001 From: Sieciech Date: Wed, 1 Sep 2021 17:52:14 +0200 Subject: [PATCH] implement part 3 --- .../migrations/Version20210901131245.php | 61 +++++++ src/backend/src/Controller/AuthController.php | 14 +- .../src/Controller/PersonController.php | 23 +++ .../src/Entity/Abstraction/BaseEntity.php | 2 +- src/backend/src/Entity/Person.php | 150 ++++++++++++++++++ src/backend/src/Entity/User.php | 89 +---------- .../src/Repository/PersonRepository.php | 48 ++++++ src/frontend/src/app/app.component.html | 4 +- src/frontend/src/app/app.component.scss | 2 + .../app/modules/auth/models/person.model.ts | 16 ++ .../src/app/modules/auth/models/user.model.ts | 18 ++- .../profile-edit-basics.component.html | 12 +- .../profile-edit-basics.component.scss | 3 + .../profile-edit-basics.component.ts | 22 +-- .../profile-edit/profile-edit.component.html | 75 ++++----- .../profile-edit/profile-edit.component.scss | 46 ++++-- .../profile-edit/profile-edit.component.ts | 81 +++++++--- .../app/modules/profile/profile-routing.ts | 5 + .../profile/service/person/person.service.ts | 17 ++ src/frontend/src/app/styles/bundles/form.scss | 22 +-- src/frontend/src/assets/lang/en.json | 1 + src/frontend/src/assets/lang/pl.json | 1 + 22 files changed, 516 insertions(+), 196 deletions(-) create mode 100644 src/backend/migrations/Version20210901131245.php create mode 100644 src/backend/src/Controller/PersonController.php create mode 100644 src/backend/src/Entity/Person.php create mode 100644 src/backend/src/Repository/PersonRepository.php create mode 100644 src/frontend/src/app/modules/auth/models/person.model.ts create mode 100644 src/frontend/src/app/modules/profile/service/person/person.service.ts diff --git a/src/backend/migrations/Version20210901131245.php b/src/backend/migrations/Version20210901131245.php new file mode 100644 index 0000000..37cc8a9 --- /dev/null +++ b/src/backend/migrations/Version20210901131245.php @@ -0,0 +1,61 @@ +addSql('CREATE SEQUENCE person_id_seq INCREMENT BY 1 MINVALUE 1 START 1'); + $this->addSql('CREATE TABLE person (id INT NOT NULL, country_id INT DEFAULT NULL, state_id INT DEFAULT NULL, name VARCHAR(255) NOT NULL, surname VARCHAR(255) NOT NULL, city VARCHAR(255) DEFAULT NULL, zip VARCHAR(7) DEFAULT NULL, avatar VARCHAR(255) DEFAULT NULL, PRIMARY KEY(id))'); + $this->addSql('CREATE INDEX IDX_34DCD176F92F3E70 ON person (country_id)'); + $this->addSql('CREATE INDEX IDX_34DCD1765D83CC1 ON person (state_id)'); + $this->addSql('ALTER TABLE person ADD CONSTRAINT FK_34DCD176F92F3E70 FOREIGN KEY (country_id) REFERENCES country (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE person ADD CONSTRAINT FK_34DCD1765D83CC1 FOREIGN KEY (state_id) REFERENCES country_region (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE "user" DROP CONSTRAINT fk_8d93d649f92f3e70'); + $this->addSql('ALTER TABLE "user" DROP CONSTRAINT fk_8d93d6495d83cc1'); + $this->addSql('DROP INDEX idx_8d93d649f92f3e70'); + $this->addSql('DROP INDEX idx_8d93d6495d83cc1'); + $this->addSql('ALTER TABLE "user" ADD person_id INT DEFAULT NULL'); + $this->addSql('ALTER TABLE "user" DROP country_id'); + $this->addSql('ALTER TABLE "user" DROP state_id'); + $this->addSql('ALTER TABLE "user" DROP name'); + $this->addSql('ALTER TABLE "user" DROP surname'); + $this->addSql('ALTER TABLE "user" DROP avatar'); + $this->addSql('ALTER TABLE "user" ADD CONSTRAINT FK_8D93D649217BBB47 FOREIGN KEY (person_id) REFERENCES person (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('CREATE UNIQUE INDEX UNIQ_8D93D649217BBB47 ON "user" (person_id)'); + } + + public function down(Schema $schema): void + { + // this down() migration is auto-generated, please modify it to your needs + $this->addSql('CREATE SCHEMA public'); + $this->addSql('ALTER TABLE "user" DROP CONSTRAINT FK_8D93D649217BBB47'); + $this->addSql('DROP SEQUENCE person_id_seq CASCADE'); + $this->addSql('DROP TABLE person'); + $this->addSql('DROP INDEX UNIQ_8D93D649217BBB47'); + $this->addSql('ALTER TABLE "user" ADD state_id INT DEFAULT NULL'); + $this->addSql('ALTER TABLE "user" ADD name VARCHAR(255) NOT NULL'); + $this->addSql('ALTER TABLE "user" ADD surname VARCHAR(255) NOT NULL'); + $this->addSql('ALTER TABLE "user" ADD avatar VARCHAR(255) DEFAULT NULL'); + $this->addSql('ALTER TABLE "user" RENAME COLUMN person_id TO country_id'); + $this->addSql('ALTER TABLE "user" ADD CONSTRAINT fk_8d93d649f92f3e70 FOREIGN KEY (country_id) REFERENCES country (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE "user" ADD CONSTRAINT fk_8d93d6495d83cc1 FOREIGN KEY (state_id) REFERENCES country_region (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('CREATE INDEX idx_8d93d649f92f3e70 ON "user" (country_id)'); + $this->addSql('CREATE INDEX idx_8d93d6495d83cc1 ON "user" (state_id)'); + } +} diff --git a/src/backend/src/Controller/AuthController.php b/src/backend/src/Controller/AuthController.php index 98aaf38..826e1dd 100644 --- a/src/backend/src/Controller/AuthController.php +++ b/src/backend/src/Controller/AuthController.php @@ -3,6 +3,7 @@ namespace App\Controller; use App\Entity\User; +use App\Entity\Person; use App\Traits\JsonResponseTrait; use App\Repository\UserRepository; use Symfony\Component\HttpFoundation\Request; @@ -37,13 +38,20 @@ class AuthController extends AbstractController return $this->notAcceptable("User email exists"); } + $person = new Person(); + $person->setName($name); + $person->setSurname($surname); + $person->generateAvatar($email); + $em->persist($person); + $em->flush(); + $user = new User(); $user->setPassword($encoder->hashPassword($user, $password)); $user->setEmail($email); - $user->setName($name); - $user->setSurname($surname); + $user->setPerson($person); $em->persist($user); $em->flush(); + return $this->created($user); } @@ -60,7 +68,7 @@ class AuthController extends AbstractController if (!$user) { return $this->unauthorized([]); } - $user->generateAvatar(); + $user->getPerson()->generateAvatar($user->getEmail()); return $this->ok($user); } } diff --git a/src/backend/src/Controller/PersonController.php b/src/backend/src/Controller/PersonController.php new file mode 100644 index 0000000..1bdf482 --- /dev/null +++ b/src/backend/src/Controller/PersonController.php @@ -0,0 +1,23 @@ +personRepository->get($personId); + return $this->ok($person); + } +} diff --git a/src/backend/src/Entity/Abstraction/BaseEntity.php b/src/backend/src/Entity/Abstraction/BaseEntity.php index bddfee2..358789b 100644 --- a/src/backend/src/Entity/Abstraction/BaseEntity.php +++ b/src/backend/src/Entity/Abstraction/BaseEntity.php @@ -15,7 +15,7 @@ class BaseEntity { $output = []; $defaultContext = [ AbstractNormalizer::CIRCULAR_REFERENCE_HANDLER => function ($object, $format, $context) { - return $object->getName(); + return '$' . basename(str_replace('\\', '/', $object::class)); }, ]; $normalizers = [new ObjectNormalizer(defaultContext: $defaultContext)]; diff --git a/src/backend/src/Entity/Person.php b/src/backend/src/Entity/Person.php new file mode 100644 index 0000000..0284a7b --- /dev/null +++ b/src/backend/src/Entity/Person.php @@ -0,0 +1,150 @@ +id; + } + + public function getName(): ?string + { + return $this->name; + } + + public function setName(string $name): self + { + $this->name = $name; + + return $this; + } + + public function getSurname(): ?string + { + return $this->surname; + } + + public function setSurname(string $surname): self + { + $this->surname = $surname; + + return $this; + } + + public function getCountry(): ?Country + { + return $this->country; + } + + public function setCountry(?Country $country): self + { + $this->country = $country; + + return $this; + } + + public function getState(): ?CountryRegion + { + return $this->state; + } + + public function setState(?CountryRegion $state): self + { + $this->state = $state; + + return $this; + } + + public function getCity(): ?string + { + return $this->city; + } + + public function setCity(string $city): self + { + $this->city = $city; + + return $this; + } + + public function getZip(): ?string + { + return $this->zip; + } + + public function setZip(string $zip): self + { + $this->zip = $zip; + + return $this; + } + + public function getAvatar(): ?string + { + return $this->avatar; + } + + public function setAvatar(string $avatar): self + { + $this->avatar = $avatar; + + return $this; + } + + public function generateAvatar($email) { + if (!$this->avatar) { + $this->avatar = 'https://www.gravatar.com/avatar/' . md5($email) . '?s=512&d=robohash'; + } + } +} diff --git a/src/backend/src/Entity/User.php b/src/backend/src/Entity/User.php index 2832e91..25dce6c 100644 --- a/src/backend/src/Entity/User.php +++ b/src/backend/src/Entity/User.php @@ -2,10 +2,11 @@ namespace App\Entity; +use App\Entity\Person; +use App\Enums\UserRoleEnum; use Doctrine\ORM\Mapping as ORM; use App\Repository\UserRepository; use App\Entity\Abstraction\BaseEntity; -use App\Enums\UserRoleEnum; use Symfony\Component\Security\Core\User\UserInterface; use Lexik\Bundle\JWTAuthenticationBundle\Security\User\JWTUserInterface; use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface; @@ -42,29 +43,9 @@ class User extends BaseEntity implements UserInterface, PasswordAuthenticatedUse private $email; /** - * @ORM\Column(type="string", length=255) + * @ORM\OneToOne(targetEntity=Person::class, cascade={"persist", "remove"}) */ - private $name; - - /** - * @ORM\Column(type="string", length=255) - */ - private $surname; - - /** - * @ORM\Column(type="string", length=255, nullable=true) - */ - private $avatar; - - /** - * @ORM\ManyToOne(targetEntity=Country::class) - */ - private $country; - - /** - * @ORM\ManyToOne(targetEntity=CountryRegion::class) - */ - private $state; + private $person; public static function createFromPayload($username, array $payload) @@ -174,68 +155,14 @@ class User extends BaseEntity implements UserInterface, PasswordAuthenticatedUse return $this; } - public function getName(): ?string + public function getPerson(): ?Person { - return $this->name; + return $this->person; } - public function setName(string $name): self + public function setPerson(?Person $person): self { - $this->name = $name; - - return $this; - } - - public function getSurname(): ?string - { - return $this->surname; - } - - public function setSurname(string $surname): self - { - $this->surname = $surname; - - return $this; - } - - public function getAvatar(): ?string - { - return $this->avatar; - } - - public function setAvatar(?string $avatar): self - { - $this->avatar = $avatar; - - return $this; - } - - public function generateAvatar() { - if (!$this->avatar) { - $this->avatar = 'https://www.gravatar.com/avatar/' . md5($this->email) . '?s=514&d=robohash'; - } - } - - public function getCountry(): ?Country - { - return $this->country; - } - - public function setCountry(?Country $country): self - { - $this->country = $country; - - return $this; - } - - public function getState(): ?CountryRegion - { - return $this->state; - } - - public function setState(?CountryRegion $state): self - { - $this->state = $state; + $this->person = $person; return $this; } diff --git a/src/backend/src/Repository/PersonRepository.php b/src/backend/src/Repository/PersonRepository.php new file mode 100644 index 0000000..8b2496c --- /dev/null +++ b/src/backend/src/Repository/PersonRepository.php @@ -0,0 +1,48 @@ +createQueryBuilder('p') + ->andWhere('p.exampleField = :val') + ->setParameter('val', $value) + ->orderBy('p.id', 'ASC') + ->setMaxResults(10) + ->getQuery() + ->getResult() + ; + } + */ + + public function get(int $personId): ?Person + { + return $this->createQueryBuilder('p') + ->andWhere('p.id = :id') + ->setParameter('id', $personId) + ->getQuery() + ->getOneOrNullResult() + ; + } +} diff --git a/src/frontend/src/app/app.component.html b/src/frontend/src/app/app.component.html index c702d4b..fd12d2b 100644 --- a/src/frontend/src/app/app.component.html +++ b/src/frontend/src/app/app.component.html @@ -41,8 +41,8 @@
-
-
{{ user.name }} {{ user.surname }}
+
+
{{ user.person.name }} {{ user.person.surname }}
-
+ + + + diff --git a/src/frontend/src/app/modules/profile/components/profile-edit-basics/profile-edit-basics.component.scss b/src/frontend/src/app/modules/profile/components/profile-edit-basics/profile-edit-basics.component.scss index 7aeb835..e8434ab 100644 --- a/src/frontend/src/app/modules/profile/components/profile-edit-basics/profile-edit-basics.component.scss +++ b/src/frontend/src/app/modules/profile/components/profile-edit-basics/profile-edit-basics.component.scss @@ -1,3 +1,6 @@ .container{ max-width: 720px; +} +.form-footer{ + width: 100%; } \ No newline at end of file diff --git a/src/frontend/src/app/modules/profile/components/profile-edit-basics/profile-edit-basics.component.ts b/src/frontend/src/app/modules/profile/components/profile-edit-basics/profile-edit-basics.component.ts index 7a83799..d5ebf89 100644 --- a/src/frontend/src/app/modules/profile/components/profile-edit-basics/profile-edit-basics.component.ts +++ b/src/frontend/src/app/modules/profile/components/profile-edit-basics/profile-edit-basics.component.ts @@ -1,10 +1,11 @@ -import { Component, OnInit } from '@angular/core'; +import { Component, ElementRef, OnInit, ViewChild } from '@angular/core'; import { FormBuilder, FormGroup } from '@ng-stack/forms'; import { Observable, Subject } from 'rxjs'; import { CountryModel } from 'src/app/modules/shared/models/country.model'; import { CountryService } from 'src/app/modules/shared/services/country/country.service'; import { map, startWith } from 'rxjs/operators'; import { AuthService } from 'src/app/modules/auth/services/auth/auth.service'; +import { ProfileEditComponent } from '../profile-edit/profile-edit.component'; interface PhoneEntry{ number: string; @@ -39,28 +40,27 @@ class ProfileInformationBasicModel { export class ProfileEditBasicsComponent implements OnInit { form: FormGroup; - onContentScroll = new Subject(); - headerHeight = 200; - placeholderBoxHeight = 0; filteredCountries: Observable; countryInputChnage = new Subject(); countries: CountryModel[] = []; countryInput = ''; + @ViewChild('footer') footerElement: ElementRef; constructor( private countryService: CountryService, authService: AuthService, formBuilder: FormBuilder, + parent: ProfileEditComponent, ) { const phones = formBuilder.array([]); const emails = formBuilder.array([]); const user = authService.getUser(); this.form = formBuilder.group({ - name: user.name, - surname: user.surname, + name: parent.person.name, + surname: parent.person.surname, - country: user.country, + country: parent.person.country, state: 'state', city: 'city', zip: 'zip', @@ -89,14 +89,6 @@ export class ProfileEditBasicsComponent implements OnInit { ngOnInit(): void { } - scroll(e): void { - const scrollTop = e.target?.scrollTop; - if (Number(scrollTop) === scrollTop) { - this.placeholderBoxHeight = Math.min(scrollTop, this.headerHeight); - this.onContentScroll.next(scrollTop); - } - } - filterCountries(name: string): CountryModel[] { return this.countries.filter(i => i.name.toLowerCase().includes(name)); } diff --git a/src/frontend/src/app/modules/profile/components/profile-edit/profile-edit.component.html b/src/frontend/src/app/modules/profile/components/profile-edit/profile-edit.component.html index d6c6548..1a888dc 100644 --- a/src/frontend/src/app/modules/profile/components/profile-edit/profile-edit.component.html +++ b/src/frontend/src/app/modules/profile/components/profile-edit/profile-edit.component.html @@ -1,46 +1,49 @@ -
-
+
+
+
+
-
-
-
- - loading - - -
-
-
-
-
-

{{ user.name }} {{ user.surname }}

-
+
+
+ + loading + + +
+
+
- +
+

{{ person.name }} {{ person.surname }}

+
+
+
+
+
+
+
{{ currentTabName | translate }}
+
+
+ + + + + + {{ tab.label | translate }} + + + +
-
-
-
{{ currentTabName | translate }}
-
-
- - - - - - {{ tab.label | translate }} - - - - +
+
+
-
-
-
- +
diff --git a/src/frontend/src/app/modules/profile/components/profile-edit/profile-edit.component.scss b/src/frontend/src/app/modules/profile/components/profile-edit/profile-edit.component.scss index 9c28b08..132cb8d 100644 --- a/src/frontend/src/app/modules/profile/components/profile-edit/profile-edit.component.scss +++ b/src/frontend/src/app/modules/profile/components/profile-edit/profile-edit.component.scss @@ -3,21 +3,19 @@ display: flex; flex-direction: column; } -.scrollable-header{ - overflow: hidden; - > * { - margin-top: calc(var(--scrolled) * -1px); - margin-bottom: calc(var(--scrolled) * -1px); - } -} .user-cover{ - height: 100px; - background-color: var(--toolbar-background); position: relative; z-index: -1; + height: 0px; + width: calc(100% - var(--scrollbar-width)); + div{ + display: block; + content: ""; + height: 100px; + background-color: var(--toolbar-background); + } } .user-header-container{ - margin-top: -100px; position: relative; z-index: 20; } @@ -42,4 +40,32 @@ } .main-background{ background: var(--main-background); +} + + +.scroller{ + position: absolute; + top: 0px; + left: 0px; + width: 100%; + height: 100%; + display: flex; + flex-direction: column; + --scrollbar-width: 0px; + .header{ + position: relative; + top: 0px; + left: 0px; + width: calc(100% - var(--scrollbar-width)); + z-index: 20; + } + .content{ + position: relative; + top: 0px; + left: 0px; + width: 100%; + height: 100%; + overflow: auto; + z-index: 10; + } } \ No newline at end of file diff --git a/src/frontend/src/app/modules/profile/components/profile-edit/profile-edit.component.ts b/src/frontend/src/app/modules/profile/components/profile-edit/profile-edit.component.ts index 05c7ce7..d60f0a7 100644 --- a/src/frontend/src/app/modules/profile/components/profile-edit/profile-edit.component.ts +++ b/src/frontend/src/app/modules/profile/components/profile-edit/profile-edit.component.ts @@ -1,12 +1,11 @@ import { AfterViewInit, Component, ElementRef, OnInit, ViewChild } from '@angular/core'; import { DomSanitizer, SafeStyle } from '@angular/platform-browser'; import { ActivatedRoute, ActivatedRouteSnapshot, ActivationStart, Data, Router, RoutesRecognized } from '@angular/router'; -import { Subscription } from 'rxjs'; -import { UserModel } from 'src/app/modules/auth/models/user.model'; +import { PersonModel } from 'src/app/modules/auth/models/person.model'; import { AuthService } from 'src/app/modules/auth/services/auth/auth.service'; import { ProfileTabEnum } from '../../enums/profile-tab.enum'; import { profileTabRoutes } from '../../profile-routing'; - +import { PersonService } from '../../service/person/person.service'; interface ProfileTab { tab: ProfileTabEnum; @@ -21,15 +20,19 @@ interface ProfileTab { }) export class ProfileEditComponent implements AfterViewInit { - scrollSubscriptions: Subscription[] = []; - scrolled = 0; profileTabRoutes = profileTabRoutes; currentTabName: string; - user: UserModel | null = null; + person: PersonModel | null = null; selectedIndex = 0; defaultProfileTab = ProfileTabEnum.Basics; + footerElement: ElementRef; loaded = false; - @ViewChild('headerContent', {static: false}) headerContent: ElementRef; + @ViewChild('scrollHeader', {static: false}) scrollHeader: ElementRef; + @ViewChild('scrollContent', {static: false}) scrollContent: ElementRef; + headerHeight = 200; + headerMove = 0; + maxHeaderMove = 0; + scrollWidth = 30; tabs: ProfileTab[] = [ { tab: ProfileTabEnum.Basics, @@ -63,11 +66,15 @@ export class ProfileEditComponent implements AfterViewInit { authService: AuthService, private activatedRoute: ActivatedRoute, private router: Router, + private personService: PersonService, ) { - this.user = authService.getUser(); - authService.userChange.subscribe(user => { - this.user = user; - }); + const personId = parseInt(activatedRoute.snapshot.params.personId, 10); + if (personId) { + this.loadPerson(personId); + } else { + this.loadPerson(authService.getUser().person.id); + } + this.onRouteChange(activatedRoute.snapshot.firstChild?.data); this.router.events.subscribe(event => { if (event instanceof RoutesRecognized) { @@ -76,28 +83,50 @@ export class ProfileEditComponent implements AfterViewInit { }); } + loadPerson(personId: number) { + this.person = undefined; + this.loaded = false; + this.personService.get(personId).subscribe(person => { + this.person = person; + this.loaded = true; + }); + } + + updateScroller() { + this.scrollHeader.nativeElement.style.height = '0px'; + this.headerHeight = this.scrollHeader.nativeElement.scrollHeight; + this.maxHeaderMove = this.scrollHeader.nativeElement.firstChild.scrollHeight; + this.scrollWidth = this.scrollContent.nativeElement.parentElement.scrollWidth - this.scrollContent.nativeElement.scrollWidth; + } + ngAfterViewInit(): void { this.loaded = true; + setTimeout(() => { + this.updateScroller(); + }, 50); } - activated(component): void { - if (component.onContentScroll) { - component.headerHeight = this.headerContent.nativeElement.scrollHeight; - setTimeout(() => { - component.headerHeight = this.headerContent.nativeElement.scrollHeight; - }, 500); - this.scrollSubscriptions.push( - component.onContentScroll.subscribe(position => { - this.scrolled = position / 2; - }) - ); + activated(component) { + if (component.footerElement) { + this.footerElement = component.footerElement; } + setTimeout(() => { + if (component.footerElement) { + this.footerElement = component.footerElement; + } + this.updateScroller(); + }, 50); } - deactivated(component): void { - this.scrolled = 0; - this.scrollSubscriptions.forEach(i => i.unsubscribe()); - this.scrollSubscriptions = []; + deactivated(component) { + this.footerElement = undefined; + setTimeout(() => { + this.updateScroller(); + }, 50); + } + + onscrol(e) { + this.headerMove = Math.min(e.target.scrollTop, this.maxHeaderMove); } onRouteChange(data: Data): void { diff --git a/src/frontend/src/app/modules/profile/profile-routing.ts b/src/frontend/src/app/modules/profile/profile-routing.ts index a943390..ab92def 100644 --- a/src/frontend/src/app/modules/profile/profile-routing.ts +++ b/src/frontend/src/app/modules/profile/profile-routing.ts @@ -51,4 +51,9 @@ export const profileRoutes: Route[] = [ component: ProfileEditComponent, children: profileTabRoutes, }, + { + path: ':personId', + component: ProfileEditComponent, + children: profileTabRoutes, + }, ]; diff --git a/src/frontend/src/app/modules/profile/service/person/person.service.ts b/src/frontend/src/app/modules/profile/service/person/person.service.ts new file mode 100644 index 0000000..1d61d3d --- /dev/null +++ b/src/frontend/src/app/modules/profile/service/person/person.service.ts @@ -0,0 +1,17 @@ +import { HttpClient } from '@angular/common/http'; +import { Injectable } from '@angular/core'; +import { Observable } from 'rxjs'; +import { PersonModel } from 'src/app/modules/auth/models/person.model'; + +@Injectable({ + providedIn: 'root' +}) +export class PersonService { + + constructor(private http: HttpClient) { + } + + get(personId: number): Observable { + return this.http.get(`/api/person/${personId}`); + } +} diff --git a/src/frontend/src/app/styles/bundles/form.scss b/src/frontend/src/app/styles/bundles/form.scss index ce5c755..4197e0b 100644 --- a/src/frontend/src/app/styles/bundles/form.scss +++ b/src/frontend/src/app/styles/bundles/form.scss @@ -1,7 +1,7 @@ .form-group{ display: flex; flex-wrap: wrap; - margin: 1rem; + padding: 1rem; &:not(:last-child){ margin-bottom: 2rem; } @@ -37,17 +37,17 @@ flex-grow: 1; padding: 0.5rem; } - .form-footer{ - background: var(--dialog-background); - border-top: 1px solid var(--divider-color); - padding: 0.5rem; +} +.form-footer{ + background: var(--dialog-background); + border-top: 1px solid var(--divider-color); + padding: 0.5rem; + display: flex; + justify-content: flex-end; + > div{ display: flex; - justify-content: flex-end; - > div{ - display: flex; - &:first-child{ - flex-grow: 1; - } + &:first-child{ + flex-grow: 1; } } } diff --git a/src/frontend/src/assets/lang/en.json b/src/frontend/src/assets/lang/en.json index 5306b06..7df0bb0 100644 --- a/src/frontend/src/assets/lang/en.json +++ b/src/frontend/src/assets/lang/en.json @@ -50,6 +50,7 @@ "AVATAR": "Avatar", "PASSWORD": "Password", "SITE_SETTINGS": "Site settings", + "SAVE": "Save", "CONTACTS": { "COUNTRY": "Country", "STATE": "State", diff --git a/src/frontend/src/assets/lang/pl.json b/src/frontend/src/assets/lang/pl.json index cea0376..e3d369a 100644 --- a/src/frontend/src/assets/lang/pl.json +++ b/src/frontend/src/assets/lang/pl.json @@ -50,6 +50,7 @@ "AVATAR": "Zdjęcie profilowe", "PASSWORD": "Hasło", "SITE_SETTINGS": "Ustawienia strony", + "SAVE": "Zapisz", "CONTACTS": { "COUNTRY": "Kraj", "STATE": "Województwo",