diff --git a/client/package.json b/client/package.json
index 2e00ec649bcfe456bef7283b02cc36f5c741f734..edef3c6d9e8ef53b84e7ff11b7252978790eb2b6 100644
--- a/client/package.json
+++ b/client/package.json
@@ -3,7 +3,7 @@
   "version": "0.0.0",
   "scripts": {
     "ng": "ng",
-    "start": "ng serve",
+    "start": "ng serve --proxy-config proxy.conf.json",
     "build": "ng build",
     "test": "ng test",
     "lint": "ng lint",
diff --git a/client/proxy.conf.json b/client/proxy.conf.json
new file mode 100644
index 0000000000000000000000000000000000000000..073c1d74ab8faeeaa52c99586b4cfb83d9f85e1d
--- /dev/null
+++ b/client/proxy.conf.json
@@ -0,0 +1,6 @@
+{
+    "/api": {
+      "target": "http://localhost:3000",
+      "secure": false
+    }
+  }
\ No newline at end of file
diff --git a/client/src/app/app-routing.module.ts b/client/src/app/app-routing.module.ts
index 9dda020f553784e279ee3261905643fc0bdb4d44..15fb2c5826cf6db2157224957e954c5df0894cfe 100644
--- a/client/src/app/app-routing.module.ts
+++ b/client/src/app/app-routing.module.ts
@@ -3,7 +3,7 @@ import { RouterModule, Routes } from '@angular/router';
 import { PostFormComponent } from './posts/post-form/post-form.component';
 
 const routes: Routes = [
-  { path: 'postForm', component: PostFormComponent }
+  { path: 'annonse/ny', component: PostFormComponent }
 ];
 
 @NgModule({
diff --git a/client/src/app/app.module.ts b/client/src/app/app.module.ts
index 008d62ffa4ea86d0af22ae53ee5711ba1859e7ea..fb29b9167c4d5cdd2f077f9fba26de35f258c19a 100644
--- a/client/src/app/app.module.ts
+++ b/client/src/app/app.module.ts
@@ -1,9 +1,11 @@
 import { NgModule } from '@angular/core';
 import { BrowserModule } from '@angular/platform-browser';
+import { HttpClientModule } from '@angular/common/http';
 
 import { AppRoutingModule } from './app-routing.module';
 import { AppComponent } from './app.component';
 import { PostModule } from './posts/post.module';
+import { SharedModule } from './shared/shared.module';
 
 @NgModule({
   declarations: [
@@ -12,7 +14,9 @@ import { PostModule } from './posts/post.module';
   imports: [
     BrowserModule,
     AppRoutingModule,
-    PostModule
+    PostModule,
+    SharedModule,
+    HttpClientModule
   ],
   providers: [],
   bootstrap: [AppComponent]
diff --git a/client/src/app/models/deserializable.model.ts b/client/src/app/models/deserializable.model.ts
index 28a3f4b28713b94f67d84a6b012ef6827defef35..8c8e258ad55ce5f0a764b64c464ba8fff463f663 100644
--- a/client/src/app/models/deserializable.model.ts
+++ b/client/src/app/models/deserializable.model.ts
@@ -1,3 +1,3 @@
 export interface Deserializable {
-    deserialize(input: string): this;
+    deserialize(input: Object): this;
 }
\ No newline at end of file
diff --git a/client/src/app/models/post.model.ts b/client/src/app/models/post.model.ts
index c712beb79683e4be2bd8457ed5d2a65830218786..3e4c006cb7243a96675b70a20b0623a594870703 100644
--- a/client/src/app/models/post.model.ts
+++ b/client/src/app/models/post.model.ts
@@ -2,72 +2,119 @@ import { Deserializable } from "./deserializable.model";
 import { Serializable } from "./serializable.model";
 
 export class Post implements Deserializable, Serializable {
+    private id: number;
     private title: string;
     private description: string;
     private timestamp: Date;
-    private user: string;
+    private owner: string;
+    private imageUrl: string;
+    private price: number;
+    private categoryid: number;
 
     constructor(input: any = null) {
         if (input) {
+            this.id = input.id;
             this.title = input.title;
             this.description = input.description;
-            this.timestamp = new Date(input.timestamp);
-            this.user = input.user;
+            this.timestamp = input.timestamp;
+            this.owner = input.owner;
+            this.imageUrl = input.imageUrl;
+            this.price = input.price;
+            this.categoryid = input.categoryid;
         } else {
-            this.title = "";
-            this.description = "";
+            this.id = 0;
+            this.title = null;
+            this.description = null;
             this.timestamp = new Date();
-            this.user = "";
+            this.owner = null;
+            this.imageUrl = null;
+            this.price = null;
+            this.categoryid = null;
         }
     }
 
-    deserialize(input: string): this {
-        const obj = JSON.parse(input);
-        Object.assign(this, obj);
+    deserialize(input: Object): this {
+        Object.assign(this, input);
 
         this.timestamp = new Date(this.timestamp);
 
         return this;
     }
 
-    serialize(): string {
-        return JSON.stringify({
+    serialize(): Object {
+        return {
+            id: this.id,
             title: this.title,
             description: this.description,
             timestamp: this.timestamp.valueOf(),
-            user: this.user
-        });
+            owner: this.owner,
+            imageUrl: this.imageUrl,
+            price: this.price,
+            categoryid: this.categoryid
+        };
     }
 
-    get getTitle () {
+    get getId() {
+        return this.id;
+    }
+
+    set setId(id: number) {
+        this.id = id;
+    }
+
+    get getTitle() {
         return this.title;
     }
 
-    set setTitle (title: string) {
+    set setTitle(title: string) {
         this.title = title;
     }
 
-    get getDescription () {
+    get getDescription() {
         return this.description;
     }
 
-    set setDescription (description: string) {
+    set setDescription(description: string) {
         this.description = description;
     }
 
-    get getTimestamp () {
+    get getTimestamp() {
         return this.timestamp;
     }
 
-    set setTimestamp (timestamp: Date) {
+    set setTimestamp(timestamp: Date) {
         this.timestamp = timestamp;
     }
 
-    get getUser () {
-        return this.user;
+    get getOwner() {
+        return this.owner;
+    }
+
+    set setOwner(owner: string) {
+        this.owner = owner;
+    }
+
+    get getImageUrl() {
+        return this.imageUrl;
+    }
+
+    set setImageUrl(imageUrl: string) {
+        this.imageUrl = imageUrl;
+    }
+
+    get getPrice() {
+        return this.price;
+    }
+
+    set setPrice(price: number) {
+        this.price = price;
+    }
+
+    get getCategory() {
+        return this.categoryid;
     }
 
-    set setUser (user: string) {
-        this.user = user;
+    set setCategory(categoryid: number) {
+        this.categoryid = categoryid;
     }
 }
\ No newline at end of file
diff --git a/client/src/app/models/serializable.model.ts b/client/src/app/models/serializable.model.ts
index 6de9e54cd0c72e4b077d9a9719c6f3c8b8a0e953..c985231b89d8481692b085038800874524855d8e 100644
--- a/client/src/app/models/serializable.model.ts
+++ b/client/src/app/models/serializable.model.ts
@@ -1,3 +1,3 @@
 export interface Serializable {
-    serialize(): string;
+    serialize(): Object;
 }
\ No newline at end of file
diff --git a/client/src/app/posts/post-form/post-form.component.html b/client/src/app/posts/post-form/post-form.component.html
index ea9250cd54564922d03bf0e8b329aa7217881b7f..e89803521b22e8a339b97868c51233890838d3f4 100644
--- a/client/src/app/posts/post-form/post-form.component.html
+++ b/client/src/app/posts/post-form/post-form.component.html
@@ -1,4 +1,18 @@
-<p>Post form!</p>
+<h3>Lag annonse</h3>
 
-<p>Title: {{deserializedPost.getTitle}}</p>
-<p>Description: {{deserializedPost.getDescription}}</p>
+<app-text-input [(inputModel)]="title" label="Tittel" (blur)="checkForm()"></app-text-input>
+
+<app-text-input [(inputModel)]="description" label="Beskrivelse" (blur)="checkForm()"></app-text-input>
+
+<app-number-input [(inputModel)]="price" label="Pris" (blur)="checkForm()"></app-number-input>
+
+<app-select [(inputModel)]="categoryid" (change)="checkForm()" label="Kategori">
+    <option value="0" selected>Velg kategori</option>
+    <option value="1">Antikviteter og Kunst</option>
+    <option value="2">Dyr og Utstyr</option>
+    <option value="3">Elektronikk og Hvitevarer</option>
+</app-select>
+
+<p>{{statusMessage}}</p>
+
+<app-button (click)="publishPost()" text="Publiser"></app-button>
\ No newline at end of file
diff --git a/client/src/app/posts/post-form/post-form.component.spec.ts b/client/src/app/posts/post-form/post-form.component.spec.ts
index edf6f54aec58f4ecd2deb0658f5c5034078ca8fa..7e82535b45a1a2c9cfa883b910a956bd3dc4ff89 100644
--- a/client/src/app/posts/post-form/post-form.component.spec.ts
+++ b/client/src/app/posts/post-form/post-form.component.spec.ts
@@ -1,14 +1,20 @@
-import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { HttpClientTestingModule } from '@angular/common/http/testing';
+import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing';
+import { FormsModule } from '@angular/forms';
+import { Router } from '@angular/router';
+import { RouterTestingModule } from '@angular/router/testing';
 
 import { PostFormComponent } from './post-form.component';
 
 describe('PostFormComponent', () => {
   let component: PostFormComponent;
   let fixture: ComponentFixture<PostFormComponent>;
+  let router: Router;
 
   beforeEach(async () => {
     await TestBed.configureTestingModule({
-      declarations: [ PostFormComponent ]
+      declarations: [ PostFormComponent ],
+      imports: [ HttpClientTestingModule, RouterTestingModule, FormsModule ]
     })
     .compileComponents();
   });
@@ -17,23 +23,52 @@ describe('PostFormComponent', () => {
     fixture = TestBed.createComponent(PostFormComponent);
     component = fixture.componentInstance;
     fixture.detectChanges();
+
+    router = TestBed.inject(Router);
   });
 
   it('should create', () => {
     expect(component).toBeTruthy();
   });
 
-  it('should serialize Post', () => {
-    expect(component.serializedPost == "").toBeFalse();
+  it('should validate form', () => {
+    expect(component.checkForm()).toBeFalse();
+    expect(component.statusMessage).toBe("Tittelen kan ikke være tom");
+
+    component.title = "Title";
+    expect(component.checkForm()).toBeFalse();
+    expect(component.statusMessage).toBe("Beskrivelsen kan ikke være tom");
+    
+    component.description = "Description";
+    component.price = -100;
+    expect(component.checkForm()).toBeFalse();
+    expect(component.statusMessage).toBe("Prisen kan ikke være negativ");
 
-    try{
-      const obj = JSON.parse(component.serializedPost);
-    }catch{
-      fail("Could not serialize");
-    }
-  })
+    component.price = null;
+    expect(component.checkForm()).toBeFalse();
+    expect(component.statusMessage).toBe("Annonsen må ha en pris");
 
-  it('should deserialize Post', () => {
-    expect(component.deserializedPost.getUser).toEqual("Admin");
-  })
+    component.price = 50;
+    expect(component.checkForm()).toBeFalse();
+    expect(component.statusMessage).toBe("Annonsen må ha en kategori");
+
+    component.categoryid = 2;
+    expect(component.checkForm()).toBeTrue();
+    expect(component.statusMessage).toBe("");
+  });
+
+  it('should stop publishing invalid post', fakeAsync(() => {
+    component.publishPost();
+    expect(component.statusMessage).toBe("Tittelen kan ikke være tom");
+  }));
+
+  it('should route after publishing post', () => {
+    component.title = "Title";
+    component.description = "Description";
+    component.price = 50;
+    component.categoryid = 2;
+    component.publishPost();
+    
+    expect(router.url).toBe('/');
+  });
 });
diff --git a/client/src/app/posts/post-form/post-form.component.ts b/client/src/app/posts/post-form/post-form.component.ts
index 7f49d9133fb35e63b975fa9da0ccb053b82406bc..5864463a491b3e0ac1ee152b7db60a0017e1b836 100644
--- a/client/src/app/posts/post-form/post-form.component.ts
+++ b/client/src/app/posts/post-form/post-form.component.ts
@@ -1,5 +1,7 @@
 import { Component, OnInit } from '@angular/core';
+import { Router } from '@angular/router';
 import { Post } from 'src/app/models/post.model';
+import { PostService } from '../post.service';
 
 @Component({
   selector: 'app-post-form',
@@ -8,20 +10,75 @@ import { Post } from 'src/app/models/post.model';
 })
 export class PostFormComponent implements OnInit {
 
-  serializedPost: string = "";
-  deserializedPost: Post = new Post();
-  
-  constructor() { }
-
-  ngOnInit(): void {
-    let post = new Post({
-      title: "TestAnnonse",
-      description: "Beskrivelse",
-      timestamp: 1612952332000,
-      user: "Admin"
-    });
-
-    this.serializedPost = post.serialize();
-    this.deserializedPost.deserialize(post.serialize());
+  title: string = "";
+  description: string = "";
+  price: number = 0;
+  categoryid: number = 0;
+
+  statusMessage: string = "";
+
+  constructor(private postService: PostService, private router: Router) { }
+
+  ngOnInit() {
+  }
+
+  /**
+   * Validates form.
+   */
+  checkForm(): boolean {
+    if (this.title == "") {
+      this.setStatusMessage("Tittelen kan ikke være tom");
+      return false;
+    }
+    if (this.description == "") {
+      this.setStatusMessage("Beskrivelsen kan ikke være tom");
+      return false;
+    }
+    if (this.price < 0) {
+      this.setStatusMessage("Prisen kan ikke være negativ");
+      return false;
+    }
+    if (this.price == null) {
+      this.setStatusMessage("Annonsen må ha en pris");
+      return false;
+    }
+    if (this.categoryid < 1) {
+      this.setStatusMessage("Annonsen må ha en kategori");
+      return false;
+    }
+
+    this.setStatusMessage("");
+    return true;
+  }
+
+  /**
+   * Publishes post if it is valid.
+   */
+  publishPost() {
+    if (this.checkForm()) {
+      let newPost = new Post({
+        title: this.title,
+        description: this.description,
+        timestamp: new Date(),
+        owner: "admin",
+        imageUrl: "",
+        price: this.price,
+        categoryid: this.categoryid
+      });
+
+      this.postService.addPost(newPost).then(status => {
+        console.log("Post was added: " + status);
+        this.router.navigateByUrl("/");
+      }).catch(error => {
+        console.log("Error adding post: " + error);
+      });
+    }
+  }
+
+  /**
+   * Sets a status message.
+   */
+  setStatusMessage(message: string){
+    this.statusMessage = message;
   }
-}
+}
\ No newline at end of file
diff --git a/client/src/app/posts/post.module.ts b/client/src/app/posts/post.module.ts
index 80a6a344243bbd98e2a125dca6b7815ca61c5a2c..5599cc30a3eb472c97bfcc9d6212aacfda387cb6 100644
--- a/client/src/app/posts/post.module.ts
+++ b/client/src/app/posts/post.module.ts
@@ -1,6 +1,8 @@
 import { NgModule } from '@angular/core';
 import { CommonModule } from '@angular/common';
 import { PostFormComponent } from './post-form/post-form.component';
+import { SharedModule } from '../shared/shared.module';
+import { FormsModule } from '@angular/forms';
 
 
 
@@ -9,7 +11,10 @@ import { PostFormComponent } from './post-form/post-form.component';
     PostFormComponent
   ],
   imports: [
-    CommonModule
+    CommonModule,
+    SharedModule,
+    FormsModule
   ]
 })
+
 export class PostModule { }
diff --git a/client/src/app/posts/post.service.spec.ts b/client/src/app/posts/post.service.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..24c073bf45c74c0c777218e4220d8f29d1f7179b
--- /dev/null
+++ b/client/src/app/posts/post.service.spec.ts
@@ -0,0 +1,128 @@
+import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';
+import { TestBed } from '@angular/core/testing';
+import { Post } from '../models/post.model';
+
+import { PostService } from './post.service';
+
+describe('PostService', () => {
+  let service: PostService;
+  let httpMock: HttpTestingController;
+
+  beforeEach(() => {
+    TestBed.configureTestingModule({
+      imports: [ HttpClientTestingModule ]
+    });
+    service = TestBed.inject(PostService);
+    httpMock = TestBed.inject(HttpTestingController);
+  });
+
+  it('should be created', () => {
+    expect(service).toBeTruthy();
+  });
+
+  describe('getPost', () => {
+    it('should get a post', () => {
+      service.getPost(1).then(post => {
+        expect(post.getId).toBe(1);
+        expect(post.getTitle).toBe("Test");
+      }).catch(error => {
+        fail();
+      });
+
+      const req = httpMock.expectOne("api/post/1");
+      expect(req.request.method).toBe("GET");
+      req.flush({
+        data: [{
+          id: 1,
+          title: "Test",
+          description: "TestDescription",
+          timestamp: 23947298,
+          owner: "user",
+          imageUrl: null,
+          price: 49,
+          categoryid: 2
+        }]
+      });
+    });
+
+    it('should reject on invalid post', () => {
+      service.getPost(2).then(post => {
+        fail();
+      }).catch(error => {});
+
+      const req = httpMock.expectOne("api/post/2");
+      expect(req.request.method).toBe("GET");
+      req.flush({
+        data: [{
+          id: 0,
+          title: "Test",
+          description: "TestDescription",
+          timestamp: 23947298
+        }]
+      });
+    });
+
+    it('should reject on http error', () => {
+      service.getPost(2).then(post => {
+        fail();
+      }).catch(error => {});
+
+      const req = httpMock.expectOne("api/post/2");
+      expect(req.request.method).toBe("GET");
+      req.error(new ErrorEvent("400"));
+    });
+  });
+
+  describe('addPost', () => {
+    it('should add a post', () => {
+      let post = new Post({
+        id: 1,
+        title: "Test",
+        description: "TestDescription",
+        timestamp: 23947298,
+        owner: "user",
+        imageUrl: null,
+        price: 49,
+        categoryid: 2
+      });
+
+      service.addPost(post)
+      .then(post => {})
+      .catch(error => {
+        fail();
+      });
+
+      const req = httpMock.expectOne("api/post/");
+      expect(req.request.method).toBe("POST");
+      expect(req.request.body).toEqual(post.serialize());
+      req.flush({
+        data: [{
+          status: "success"
+        }]
+      });
+    });
+
+    it('should reject on http error', () => {
+      let post = new Post({
+        id: 1,
+        title: "Test",
+        description: "TestDescription",
+        timestamp: 23947298,
+        owner: "user",
+        imageUrl: null,
+        price: 49,
+        categoryid: 2
+      });
+
+      service.addPost(post).then(post => {
+        fail();
+      }).catch(error => {});
+
+      const req = httpMock.expectOne("api/post/");
+      expect(req.request.method).toBe("POST");
+      expect(req.request.body).toEqual(post.serialize());
+      req.error(new ErrorEvent("400"));
+    });
+  });
+});
+
diff --git a/client/src/app/posts/post.service.ts b/client/src/app/posts/post.service.ts
new file mode 100644
index 0000000000000000000000000000000000000000..e476800c7e5c82b55cb3c2c5f4ad54c4bfe784c3
--- /dev/null
+++ b/client/src/app/posts/post.service.ts
@@ -0,0 +1,69 @@
+import { HttpClient } from '@angular/common/http';
+import { Injectable } from '@angular/core';
+import { Post } from '../models/post.model';
+
+@Injectable({
+  providedIn: 'root'
+})
+export class PostService {
+
+  postUrl = "api/post/";
+
+  constructor(private http: HttpClient) { }
+
+  /**
+   * Get post from database by id.
+   */
+  getPost(id: number): Promise<Post> {
+    return new Promise<Post>(
+      (resolve, reject) => {
+        this.get_post(id).subscribe((data: any) => {
+          try {
+            const post = new Post();
+            post.deserialize(data.data[0]);
+            if (post.getId == 0) {
+              reject("Could not find Post with id: " + id);
+              return;
+            }
+            resolve(post);
+          } catch (err: any) {
+            reject(err);
+          }
+        },
+        (err: any) => {
+          console.log(err.message);
+          reject(err);
+        });
+      }
+    );
+  }
+
+  private get_post(id: number) {
+    return this.http.get(this.postUrl + id);
+  }
+
+  /**
+   * Adds post to database.
+   */
+  addPost(post: Post): Promise<string> {
+    return new Promise<string>(
+      (resolve, reject) => {
+        this.add_post(post).subscribe((data: any) => {
+          try {
+            resolve(data.status);
+          } catch (err: any) {
+            reject(err);
+          }
+        },
+        (err: any) => {
+          console.log(err.message);
+          reject(err);
+        });
+      }
+    );
+  }
+
+  private add_post(post: Post) {
+    return this.http.post(this.postUrl, post.serialize());
+  }
+}
diff --git a/client/src/app/shared/button/button.component.html b/client/src/app/shared/button/button.component.html
new file mode 100644
index 0000000000000000000000000000000000000000..e9923aa14c1888b601d72e264f828fe50b25bcdd
--- /dev/null
+++ b/client/src/app/shared/button/button.component.html
@@ -0,0 +1 @@
+<button>{{text}}</button>
\ No newline at end of file
diff --git a/client/src/app/shared/button/button.component.scss b/client/src/app/shared/button/button.component.scss
new file mode 100644
index 0000000000000000000000000000000000000000..2b4a21691f5cafa5567332acbf906bd2c7ef3e96
--- /dev/null
+++ b/client/src/app/shared/button/button.component.scss
@@ -0,0 +1,3 @@
+button{
+    padding: 5px;
+}
\ No newline at end of file
diff --git a/client/src/app/shared/button/button.component.spec.ts b/client/src/app/shared/button/button.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..534a5bace070a9697ef6a711b5ef0ea5e4ed3044
--- /dev/null
+++ b/client/src/app/shared/button/button.component.spec.ts
@@ -0,0 +1,25 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { ButtonComponent } from './button.component';
+
+describe('ButtonComponent', () => {
+  let component: ButtonComponent;
+  let fixture: ComponentFixture<ButtonComponent>;
+
+  beforeEach(async () => {
+    await TestBed.configureTestingModule({
+      declarations: [ ButtonComponent ]
+    })
+    .compileComponents();
+  });
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(ButtonComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});
diff --git a/client/src/app/shared/button/button.component.ts b/client/src/app/shared/button/button.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..605e843429c308bf9d6376e96b188b082580bcc7
--- /dev/null
+++ b/client/src/app/shared/button/button.component.ts
@@ -0,0 +1,15 @@
+import { Component, EventEmitter, Input, Output } from '@angular/core';
+
+@Component({
+  selector: 'app-button',
+  templateUrl: './button.component.html',
+  styleUrls: ['./button.component.scss']
+})
+export class ButtonComponent {
+
+  @Input()
+  text: string;
+
+  constructor() { }
+
+}
diff --git a/client/src/app/shared/number-input/number-input.component.html b/client/src/app/shared/number-input/number-input.component.html
new file mode 100644
index 0000000000000000000000000000000000000000..f8ce8b67272283b12e63b800ad8c9adedba48fe9
--- /dev/null
+++ b/client/src/app/shared/number-input/number-input.component.html
@@ -0,0 +1,12 @@
+<label>
+    {{label}}
+
+    <input  
+    type="number"
+    [placeholder]="placeholder"
+    [(ngModel)]="inputModel" 
+    (ngModelChange)="inputModelChange.emit(inputModel)" 
+    (change)="change.emit($event)"
+    (focus)="focus.emit($event)"
+    (blur)="blur.emit($event)">
+</label>
\ No newline at end of file
diff --git a/client/src/app/shared/number-input/number-input.component.scss b/client/src/app/shared/number-input/number-input.component.scss
new file mode 100644
index 0000000000000000000000000000000000000000..00cdc2a928d04283ff39dc2652060db7868d0e76
--- /dev/null
+++ b/client/src/app/shared/number-input/number-input.component.scss
@@ -0,0 +1,3 @@
+input{
+    padding: 5px;
+}
\ No newline at end of file
diff --git a/client/src/app/shared/number-input/number-input.component.spec.ts b/client/src/app/shared/number-input/number-input.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..2ff4b9f58e39fd3382d19ef53f1a2e00d68d8806
--- /dev/null
+++ b/client/src/app/shared/number-input/number-input.component.spec.ts
@@ -0,0 +1,25 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { NumberInputComponent } from './number-input.component';
+
+describe('NumberInputComponent', () => {
+  let component: NumberInputComponent;
+  let fixture: ComponentFixture<NumberInputComponent>;
+
+  beforeEach(async () => {
+    await TestBed.configureTestingModule({
+      declarations: [ NumberInputComponent ]
+    })
+    .compileComponents();
+  });
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(NumberInputComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});
diff --git a/client/src/app/shared/number-input/number-input.component.ts b/client/src/app/shared/number-input/number-input.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..7552012c3161631122fd63086d2b894d156a2c50
--- /dev/null
+++ b/client/src/app/shared/number-input/number-input.component.ts
@@ -0,0 +1,33 @@
+import { Component, EventEmitter, Input, Output } from '@angular/core';
+
+@Component({
+  selector: 'app-number-input',
+  templateUrl: './number-input.component.html',
+  styleUrls: ['./number-input.component.scss']
+})
+export class NumberInputComponent {
+
+  @Input()
+  label: string = "";
+
+  @Input()
+  inputModel: number;
+
+  @Input()
+  placeholder: string = "";
+
+  @Output()
+  inputModelChange = new EventEmitter<number>();
+
+  @Output()
+  change = new EventEmitter();
+
+  @Output()
+  focus = new EventEmitter();
+
+  @Output()
+  blur = new EventEmitter();
+
+  constructor() { }
+
+}
diff --git a/client/src/app/shared/select/select.component.html b/client/src/app/shared/select/select.component.html
new file mode 100644
index 0000000000000000000000000000000000000000..e7e4e7f86b22bf7eda4ff7658b280319b5732faf
--- /dev/null
+++ b/client/src/app/shared/select/select.component.html
@@ -0,0 +1,13 @@
+<label>
+    {{label}}
+    
+    <select
+        [(ngModel)]="inputModel"
+        (ngModelChange)="inputModelChange.emit($event)"
+        (change)="change.emit($event)"
+        (focus)="focus.emit($event)"
+        (blur)="blur.emit($event)">
+
+        <ng-content></ng-content>
+    </select>
+</label>
\ No newline at end of file
diff --git a/client/src/app/shared/select/select.component.scss b/client/src/app/shared/select/select.component.scss
new file mode 100644
index 0000000000000000000000000000000000000000..ffd6836a1cd0aa70df1d79d3954db1353fb96358
--- /dev/null
+++ b/client/src/app/shared/select/select.component.scss
@@ -0,0 +1,3 @@
+select{
+    padding: 5px;
+}
\ No newline at end of file
diff --git a/client/src/app/shared/select/select.component.spec.ts b/client/src/app/shared/select/select.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..2fb4207eb6dd5656d0ae4555b2ae7dbec7b18249
--- /dev/null
+++ b/client/src/app/shared/select/select.component.spec.ts
@@ -0,0 +1,25 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { SelectComponent } from './select.component';
+
+describe('SelectComponent', () => {
+  let component: SelectComponent;
+  let fixture: ComponentFixture<SelectComponent>;
+
+  beforeEach(async () => {
+    await TestBed.configureTestingModule({
+      declarations: [ SelectComponent ]
+    })
+    .compileComponents();
+  });
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(SelectComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});
diff --git a/client/src/app/shared/select/select.component.ts b/client/src/app/shared/select/select.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..81e1d4b76487d922f1a8e89a08ac637aed69db77
--- /dev/null
+++ b/client/src/app/shared/select/select.component.ts
@@ -0,0 +1,33 @@
+import { Component, EventEmitter, Input, Output } from '@angular/core';
+
+@Component({
+  selector: 'app-select',
+  templateUrl: './select.component.html',
+  styleUrls: ['./select.component.scss']
+})
+export class SelectComponent {
+
+  @Input()
+  label: string = "";
+
+  @Input()
+  inputModel: any;
+
+  @Input()
+  placeholder: string = "";
+
+  @Output()
+  inputModelChange = new EventEmitter<any>();
+
+  @Output()
+  change = new EventEmitter();
+
+  @Output()
+  focus = new EventEmitter();
+
+  @Output()
+  blur = new EventEmitter();
+
+  constructor() { }
+
+}
diff --git a/client/src/app/shared/shared.module.ts b/client/src/app/shared/shared.module.ts
new file mode 100644
index 0000000000000000000000000000000000000000..8459044413a154cba6617960c61140ff610119a9
--- /dev/null
+++ b/client/src/app/shared/shared.module.ts
@@ -0,0 +1,28 @@
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { TextInputComponent } from './text-input/text-input.component';
+import { FormsModule } from '@angular/forms';
+import { NumberInputComponent } from './number-input/number-input.component';
+import { ButtonComponent } from './button/button.component';
+import { SelectComponent } from './select/select.component';
+
+
+@NgModule({
+  declarations: [
+    TextInputComponent,
+    NumberInputComponent,
+    ButtonComponent,
+    SelectComponent
+  ],
+  exports: [
+    TextInputComponent,
+    NumberInputComponent,
+    ButtonComponent,
+    SelectComponent
+  ],
+  imports: [
+    CommonModule,
+    FormsModule
+  ]
+})
+export class SharedModule { }
diff --git a/client/src/app/shared/text-input/text-input.component.html b/client/src/app/shared/text-input/text-input.component.html
new file mode 100644
index 0000000000000000000000000000000000000000..52b28fdbbc7203ad4112161373da422493c40812
--- /dev/null
+++ b/client/src/app/shared/text-input/text-input.component.html
@@ -0,0 +1,12 @@
+<label>
+    {{label}}
+
+    <input  
+    type="text"
+    [placeholder]="placeholder"
+    [(ngModel)]="inputModel" 
+    (ngModelChange)="inputModelChange.emit(inputModel)" 
+    (change)="change.emit($event)"
+    (focus)="focus.emit($event)"
+    (blur)="blur.emit($event)">
+</label>
\ No newline at end of file
diff --git a/client/src/app/shared/text-input/text-input.component.scss b/client/src/app/shared/text-input/text-input.component.scss
new file mode 100644
index 0000000000000000000000000000000000000000..00cdc2a928d04283ff39dc2652060db7868d0e76
--- /dev/null
+++ b/client/src/app/shared/text-input/text-input.component.scss
@@ -0,0 +1,3 @@
+input{
+    padding: 5px;
+}
\ No newline at end of file
diff --git a/client/src/app/shared/text-input/text-input.component.spec.ts b/client/src/app/shared/text-input/text-input.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..f895776fe5022ace055990ea6f39868f964b89ec
--- /dev/null
+++ b/client/src/app/shared/text-input/text-input.component.spec.ts
@@ -0,0 +1,25 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { TextInputComponent } from './text-input.component';
+
+describe('TextInputComponent', () => {
+  let component: TextInputComponent;
+  let fixture: ComponentFixture<TextInputComponent>;
+
+  beforeEach(async () => {
+    await TestBed.configureTestingModule({
+      declarations: [ TextInputComponent ]
+    })
+    .compileComponents();
+  });
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(TextInputComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});
diff --git a/client/src/app/shared/text-input/text-input.component.ts b/client/src/app/shared/text-input/text-input.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..91d87eda8cfd55ced747f08e947a7a4f069b46d6
--- /dev/null
+++ b/client/src/app/shared/text-input/text-input.component.ts
@@ -0,0 +1,33 @@
+import { Component, EventEmitter, Input, Output } from '@angular/core';
+
+@Component({
+  selector: 'app-text-input',
+  templateUrl: './text-input.component.html',
+  styleUrls: ['./text-input.component.scss']
+})
+export class TextInputComponent {
+  
+  @Input()
+  label: string = "";
+
+  @Input()
+  inputModel: string;
+
+  @Input()
+  placeholder: string = "";
+
+  @Output()
+  inputModelChange = new EventEmitter<string>();
+
+  @Output()
+  change = new EventEmitter();
+
+  @Output()
+  focus = new EventEmitter();
+
+  @Output()
+  blur = new EventEmitter();
+
+  constructor() { }
+
+}
diff --git a/client/tsconfig.json b/client/tsconfig.json
index 94a24fe1e0e50466983817942286c5d1103f5092..b8d1a820f45ae5489b9f62d8a3daa1e9c27ae39a 100644
--- a/client/tsconfig.json
+++ b/client/tsconfig.json
@@ -5,7 +5,7 @@
     "baseUrl": "./",
     "outDir": "./dist/out-tsc",
     "forceConsistentCasingInFileNames": true,
-    "strict": true,
+    "strict": false,
     "noImplicitReturns": true,
     "noFallthroughCasesInSwitch": true,
     "sourceMap": true,