Skip to content

Commit f7ae580

Browse files
committed
Merge remote-tracking branch 'origin/main'
2 parents 008b463 + 19a34f2 commit f7ae580

49 files changed

Lines changed: 1104 additions & 502 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { Pipe, PipeTransform } from '@angular/core';
2+
3+
@Pipe({
4+
name: 'userNameExtractor'
5+
})
6+
export class UserNameExtractorPipe implements PipeTransform {
7+
8+
transform(value: unknown, ...args: unknown[]): string {
9+
const name = value?.toString() ?? "";
10+
const split = name.split(" ")
11+
if(split.length <= 1){
12+
return name.at(0)?.toUpperCase() || 'UK';
13+
}
14+
15+
return (split[0][0] + split[1][0])?.toUpperCase() || 'UK';
16+
}
17+
18+
}

apps/fakeoverflow-angular/src/app/app.routes.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,14 +38,14 @@ export const routes: Routes = [
3838
},
3939
{
4040
path: ":id",
41-
loadComponent: () => import('./pages/home/home/details/details').then(m => m.DetailsComponent),
41+
loadComponent: () => import('./pages/home/home/view-question/view-question').then(m => m.ViewQuestion),
4242
title: 'Post | FakeOverflow'
4343
}
4444
]
4545
},
4646
{ path: 'update', loadComponent: () => import('./pages/home/home/UpdatePost/update').then(m => m.UpdateComponent) },
47-
{ path: 'detail', loadComponent: () => import('@pages/home/home/details/details').then(m => m.DetailsComponent) },
48-
{ path: 'personalhome', loadComponent: () => import('./pages/home/home/PersonalQuestionsHome/personalHome').then(m => m.PersonalHome) },
47+
{ path: 'personalhome', loadComponent: () => import('./pages/home/home/PersonalQuestionsHome/personalHome').then(m => m.PersonalHome) },
48+
{ path: 'view-question', loadComponent: () => import('./pages/home/home/view-question/view-question').then(m => m.ViewQuestion), title: 'View Question | FakeOverflow' },
4949

5050
{ path: '', redirectTo: 'home', pathMatch: 'full' },
5151
{ path: '**', redirectTo: 'home' },
Lines changed: 153 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,157 @@
11
<app-navbar></app-navbar>
22
<div class="min-h-screen bg-gray-50">
3-
<div class="max-w-[900px] mx-auto px-4 sm:px-6 lg:px-8 py-8">
4-
<h1 class="text-3xl font-bold text-gray-900 mb-6">Ask question</h1>
5-
6-
<form [formGroup]="formGroup" (ngSubmit)="submit()" novalidate class="bg-white rounded-lg shadow-sm border border-gray-200 p-6 space-y-6">
7-
<div>
8-
<label class="block text-sm font-medium text-gray-700 mb-2">Title</label>
9-
<input formControlName="title" name="title" class="w-full px-4 py-2.5 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500" placeholder="Please enter your title">
10-
<div class="mt-1 text-sm text-red-600" *ngIf="formGroup.controls['title']?.touched && formGroup.controls['title']?.invalid">Enter at least 10 characters</div>
3+
<div class="max-w-[100rem] mx-auto flex flex-col lg:flex-row gap-8 px-6 lg:px-10 py-10">
4+
<div class="flex-1 space-y-6">
5+
<div class="bg-white border border-gray-200 rounded-lg shadow-sm p-6">
6+
<a routerLink="/home"
7+
class="inline-flex items-center gap-2 text-[#3a5b9d] hover:text-[#2d4879] font-medium text-sm mb-4 transition-colors group">
8+
<svg class="w-5 h-5 transition-transform group-hover:-translate-x-1" fill="none" stroke="currentColor"
9+
viewBox="0 0 24 24">
10+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 19l-7-7m0 0l7-7m-7 7h18" />
11+
</svg>
12+
Back to Home
13+
</a>
14+
<h1 class="text-3xl font-semibold text-gray-900 mb-2">Ask a Question</h1>
15+
<p class="text-sm text-gray-600">Get help from our community of developers and experts</p>
1116
</div>
12-
13-
<div>
14-
<label class="block text-sm font-medium text-gray-700 mb-2">Body</label>
15-
<textarea name="body" formControlName="content" rows="8" class="w-full px-4 py-2.5 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500" placeholder="Describle the post in detail"></textarea>
16-
<div class="mt-1 text-sm text-red-600" *ngIf="formGroup.controls['title']?.touched && formGroup.controls['title']?.invalid">Enter at least 20 characters</div>
17-
</div>
18-
<div class="flex items-center justify-between">
19-
<button type="submit" [disabled]="formGroup.invalid || loading" class="px-6 py-2.5 bg-blue-600 hover:bg-blue-700 text-white font-semibold rounded-lg disabled:opacity-50">Post your question</button>
20-
<div *ngIf="submitted" class="text-sm text-green-700">Submitted</div>
21-
</div>
22-
</form>
17+
<form [formGroup]="formGroup" (ngSubmit)="submit()" novalidate class="space-y-6">
18+
<div class="bg-white border border-gray-200 rounded-lg shadow-sm p-6">
19+
<label class="block text-lg font-semibold text-gray-900 mb-3">
20+
Title
21+
<span class="text-red-500">*</span>
22+
</label>
23+
<p class="text-sm text-gray-600 mb-4">Be specific and imagine you're asking a question to another person</p>
24+
<input formControlName="title" name="title"
25+
class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-all text-base"
26+
placeholder="e.g., How do I implement authentication in Angular 18?">
27+
<div class="mt-2 text-sm text-red-600 flex items-start gap-2"
28+
*ngIf="formGroup.controls['title']?.touched && formGroup.controls['title']?.invalid">
29+
<svg class="w-5 h-5 flex-shrink-0 mt-0.5" fill="currentColor" viewBox="0 0 20 20">
30+
<path fill-rule="evenodd"
31+
d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7 4a1 1 0 11-2 0 1 1 0 012 0zm-1-9a1 1 0 00-1 1v4a1 1 0 102 0V6a1 1 0 00-1-1z"
32+
clip-rule="evenodd" />
33+
</svg>
34+
<span>Enter at least 10 characters</span>
35+
</div>
36+
</div>
37+
<div class="bg-white border border-gray-200 rounded-lg shadow-sm p-6">
38+
<label class="block text-lg font-semibold text-gray-900 mb-3">
39+
Body
40+
<span class="text-red-500">*</span>
41+
</label>
42+
<p class="text-sm text-gray-600 mb-4">Include all the information someone would need to answer your question
43+
</p>
44+
<textarea name="body" formControlName="content" rows="12"
45+
class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-all resize-y text-base"
46+
placeholder="Describe your problem in detail. Include what you've tried and what you expected to happen..."></textarea>
47+
<div class="mt-2 text-sm text-red-600 flex items-start gap-2"
48+
*ngIf="formGroup.controls['content']?.touched && formGroup.controls['content']?.invalid">
49+
<svg class="w-5 h-5 flex-shrink-0 mt-0.5" fill="currentColor" viewBox="0 0 20 20">
50+
<path fill-rule="evenodd"
51+
d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7 4a1 1 0 11-2 0 1 1 0 012 0zm-1-9a1 1 0 00-1 1v4a1 1 0 102 0V6a1 1 0 00-1-1z"
52+
clip-rule="evenodd" />
53+
</svg>
54+
<span>Enter at least 20 characters</span>
55+
</div>
56+
<div class="flex items-center gap-2 mt-4 pt-4 border-t border-gray-100">
57+
<button type="button"
58+
class="px-3 py-1.5 text-sm text-gray-600 hover:text-blue-600 hover:bg-blue-50 rounded transition-colors flex items-center gap-1">
59+
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
60+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
61+
d="M6 2L3 6v14a2 2 0 002 2h14a2 2 0 002-2V6l-3-4z" />
62+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 6h18" />
63+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M16 10a4 4 0 01-8 0" />
64+
</svg>
65+
Attach File
66+
</button>
67+
<button type="button"
68+
class="px-3 py-1.5 text-sm text-gray-600 hover:text-blue-600 hover:bg-blue-50 rounded transition-colors flex items-center gap-1">
69+
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
70+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h7" />
71+
</svg>
72+
Format
73+
</button>
74+
<button type="button"
75+
class="px-3 py-1.5 text-sm text-gray-600 hover:text-blue-600 hover:bg-blue-50 rounded transition-colors flex items-center gap-1">
76+
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
77+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
78+
d="M10 20l4-16m4 4l4 4-4 4M6 16l-4-4 4-4" />
79+
</svg>
80+
Code
81+
</button>
82+
</div>
83+
</div>
84+
<div class="bg-white border border-gray-200 rounded-lg shadow-sm p-6">
85+
<label class="block text-lg font-semibold text-gray-900 mb-3">
86+
Tags
87+
<span class="text-gray-500 text-sm font-normal ml-2">(Optional)</span>
88+
</label>
89+
<p class="text-sm text-gray-600 mb-4">Add up to 5 tags to describe what your question is about</p>
90+
<input type="text"
91+
class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-all text-base"
92+
placeholder="e.g., angular, authentication, typescript">
93+
<div class="mt-3 flex flex-wrap gap-2">
94+
<span class="inline-flex items-center gap-1 px-3 py-1.5 bg-[#e1ecf4] text-[#39739d] rounded-sm text-sm">
95+
angular
96+
<button type="button" class="hover:text-red-600">
97+
<svg class="w-4 h-4" fill="currentColor" viewBox="0 0 20 20">
98+
<path fill-rule="evenodd"
99+
d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z"
100+
clip-rule="evenodd" />
101+
</svg>
102+
</button>
103+
</span>
104+
<span class="inline-flex items-center gap-1 px-3 py-1.5 bg-[#e1ecf4] text-[#39739d] rounded-sm text-sm">
105+
authentication
106+
<button type="button" class="hover:text-red-600">
107+
<svg class="w-4 h-4" fill="currentColor" viewBox="0 0 20 20">
108+
<path fill-rule="evenodd"
109+
d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z"
110+
clip-rule="evenodd" />
111+
</svg>
112+
</button>
113+
</span>
114+
</div>
115+
</div>
116+
<div class="bg-white border border-gray-200 rounded-lg shadow-sm p-6">
117+
<div class="flex flex-col sm:flex-row items-start sm:items-center justify-between gap-4">
118+
<div class="flex items-center gap-3">
119+
<button type="submit" [disabled]="formGroup.invalid || loading"
120+
class="px-8 py-3 bg-blue-600 hover:bg-blue-700 text-white font-semibold rounded-lg shadow-sm hover:shadow-md transition-all duration-200 disabled:opacity-50 disabled:cursor-not-allowed flex items-center gap-2">
121+
<svg *ngIf="!loading" class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
122+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4v16m8-8H4" />
123+
</svg>
124+
<svg *ngIf="loading" class="animate-spin h-5 w-5" fill="none" viewBox="0 0 24 24">
125+
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
126+
<path class="opacity-75" fill="currentColor"
127+
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z">
128+
</path>
129+
</svg>
130+
{{loading ? 'Posting...' : 'Post Your Question'}}
131+
</button>
132+
<a routerLink="/home"
133+
class="px-6 py-3 bg-white hover:bg-gray-50 text-gray-700 font-medium rounded-lg border border-gray-300 hover:border-gray-400 transition-all duration-200">
134+
Cancel
135+
</a>
136+
</div>
137+
<div *ngIf="submitted"
138+
class="flex items-center gap-2 text-sm text-green-700 font-medium bg-green-50 px-4 py-2 rounded-lg">
139+
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 20 20">
140+
<path fill-rule="evenodd"
141+
d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z"
142+
clip-rule="evenodd" />
143+
</svg>
144+
Question posted successfully!
145+
</div>
146+
</div>
147+
</div>
148+
</form>
149+
</div>
150+
<aside class="hidden lg:block w-[300px] shrink-0 space-y-6">
151+
<div class="lg:sticky lg:top-6 space-y-6">
152+
<app-community-stats></app-community-stats>
153+
<app-trending-tags></app-trending-tags>
154+
</div>
155+
</aside>
23156
</div>
24-
</div>
157+
</div>
Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,60 @@
11
import {Component, inject} from '@angular/core';
2-
import { CommonModule } from '@angular/common';
3-
import {FormControl, FormGroup, FormsModule, NgForm, ReactiveFormsModule, Validators} from '@angular/forms';
2+
import {CommonModule} from '@angular/common';
3+
import {FormControl, FormGroup, FormsModule, ReactiveFormsModule, Validators} from '@angular/forms';
4+
import {RouterLink} from '@angular/router';
45
import {Navbar} from '@shared/navbar/navbar';
6+
import {CommunityStats} from '@shared/community-stats/community-stats';
7+
import {TrendingTags} from '@shared/trending-tags/trending-tags';
58
import {PostService} from '../../../../../../../../packages/fakeoverflow-angular-services';
69

7-
810
@Component({
911
selector: 'app-post',
1012
standalone: true,
11-
imports: [Navbar, CommonModule, FormsModule, ReactiveFormsModule],
13+
imports: [
14+
CommonModule,
15+
FormsModule,
16+
ReactiveFormsModule,
17+
RouterLink,
18+
Navbar,
19+
CommunityStats,
20+
TrendingTags
21+
],
1222
templateUrl: './post.html',
1323
styleUrl: './post.scss'
1424
})
1525
export class PostComponent {
16-
17-
private readonly postService = inject(PostService)
26+
private readonly postService = inject(PostService);
1827

1928
protected readonly formGroup = new FormGroup({
2029
title: new FormControl(null, [Validators.required]),
2130
content: new FormControl(null, [Validators.required]),
22-
})
31+
});
2332

2433
loading = false;
2534
submitted = false;
2635

2736
submit() {
2837
if (this.formGroup.invalid) return;
38+
2939
console.log(this.formGroup.value);
3040
this.loading = true;
41+
3142
this.postService.createPost(this.formGroup.value as any)
3243
.subscribe({
3344
next: (response) => {
3445
console.log(response);
46+
this.submitted = true;
47+
this.loading = false;
48+
this.formGroup.reset();
49+
50+
setTimeout(() => {
51+
this.submitted = false;
52+
}, 3000);
3553
},
3654
error: (err) => {
3755
console.error(err);
56+
this.loading = false;
3857
}
39-
})
40-
this.submitted = true;
41-
this.loading = false;
42-
this.formGroup.reset();
58+
});
4359
}
4460
}

apps/fakeoverflow-angular/src/app/pages/home/home/details/details.html

Lines changed: 0 additions & 28 deletions
This file was deleted.

apps/fakeoverflow-angular/src/app/pages/home/home/details/details.ts

Lines changed: 0 additions & 54 deletions
This file was deleted.

0 commit comments

Comments
 (0)