├── src ├── assets │ ├── .gitkeep │ ├── imgs │ │ ├── default.jpg │ │ ├── home │ │ │ ├── h1.png │ │ │ ├── h2.jpg │ │ │ └── image.jpg │ │ └── agora.svg │ ├── photos │ │ ├── Agoura.png │ │ ├── verify.jpg │ │ ├── avatar02.png │ │ ├── mostafaa.jpeg │ │ └── omar-1.jpeg │ └── images │ │ ├── Visa.svg.png │ │ ├── sgin_up.jpg │ │ ├── Google-Icon.jpg │ │ ├── not-default.png │ │ ├── login_london.jpg │ │ ├── MasterCard_Logo.svg.png │ │ ├── icons8-facebook-48.png │ │ ├── icons8-apple-logo-50.png │ │ └── icons8-apple-logo.svg ├── app │ ├── app.component.css │ ├── Components │ │ ├── layout │ │ │ ├── layout.component.css │ │ │ ├── layout.component.html │ │ │ └── layout.component.ts │ │ ├── mytoast │ │ │ ├── mytoast.component.css │ │ │ ├── mytoast.component.ts │ │ │ └── mytoast.component.html │ │ ├── offcanvas │ │ │ ├── offcanvas.component.css │ │ │ ├── offcanvas.component.ts │ │ │ └── offcanvas.component.html │ │ ├── Profile │ │ │ ├── bids │ │ │ │ ├── bids.component.css │ │ │ │ ├── bids.component.html │ │ │ │ └── bids.component.ts │ │ │ ├── apartments │ │ │ │ ├── apartments.component.css │ │ │ │ ├── apartments.component.html │ │ │ │ └── apartments.component.ts │ │ │ ├── orders │ │ │ │ ├── orders.component.css │ │ │ │ ├── orders.component.html │ │ │ │ └── orders.component.ts │ │ │ ├── changepass │ │ │ │ ├── changepass.component.html │ │ │ │ ├── changepass.component.ts │ │ │ │ └── changepass.component.css │ │ │ ├── EditProfile │ │ │ │ └── edit-profile │ │ │ │ │ ├── edit-profile.component.css │ │ │ │ │ ├── edit-profile.component.html │ │ │ │ │ └── edit-profile.component.ts │ │ │ └── profile │ │ │ │ ├── profile.component.ts │ │ │ │ ├── profile.component.html │ │ │ │ └── profile.component.css │ │ ├── bid-history │ │ │ ├── bid-history.component.css │ │ │ ├── bid-history.component.ts │ │ │ └── bid-history.component.html │ │ ├── dashboard │ │ │ ├── views │ │ │ │ ├── bids │ │ │ │ │ ├── bids.component.css │ │ │ │ │ ├── bids.component.ts │ │ │ │ │ └── bids.component.html │ │ │ │ ├── charts │ │ │ │ │ ├── charts.component.css │ │ │ │ │ ├── charts.component.html │ │ │ │ │ └── charts.component.ts │ │ │ │ ├── dashboard-users │ │ │ │ │ ├── dashboard-users.component.css │ │ │ │ │ ├── dashboard-users.component.html │ │ │ │ │ └── dashboard-users.component.ts │ │ │ │ └── dashboard-bid-details │ │ │ │ │ ├── dashboard-bid-details.component.css │ │ │ │ │ └── dashboard-bid-details.component.ts │ │ │ └── containers │ │ │ │ ├── index.ts │ │ │ │ └── default-layout │ │ │ │ ├── default-footer │ │ │ │ ├── default-footer.component.scss │ │ │ │ ├── default-footer.component.html │ │ │ │ └── default-footer.component.ts │ │ │ │ ├── default-header │ │ │ │ ├── default-header.component.scss │ │ │ │ ├── default-header.component.ts │ │ │ │ └── default-header.component.html │ │ │ │ ├── index.ts │ │ │ │ ├── _nav.ts │ │ │ │ ├── default-layout.component.ts │ │ │ │ └── default-layout.component.html │ │ ├── footer-lower │ │ │ ├── footer-lower.component.css │ │ │ ├── footer-lower.component.html │ │ │ └── footer-lower.component.ts │ │ ├── login-modal │ │ │ ├── login-modal.component.css │ │ │ ├── login-modal.component.html │ │ │ └── login-modal.component.ts │ │ ├── category-scroller │ │ │ ├── category-scroller.component.css │ │ │ ├── category-scroller.component.html │ │ │ └── category-scroller.component.ts │ │ ├── edit-product-form │ │ │ ├── edit-product-form.component.css │ │ │ ├── edit-product-form.component.html │ │ │ └── edit-product-form.component.ts │ │ ├── footer-column │ │ │ ├── footer-column.component.css │ │ │ ├── footer-column.component.html │ │ │ └── footer-column.component.ts │ │ ├── create-product-form │ │ │ ├── create-product-form.component.css │ │ │ └── create-product-form.component.ts │ │ ├── Auth │ │ │ ├── thirdPartyLoginButtons │ │ │ │ ├── google-button │ │ │ │ │ ├── google-button.component.css │ │ │ │ │ ├── google-button.component.html │ │ │ │ │ └── google-button.component.ts │ │ │ │ └── facebook-button │ │ │ │ │ ├── facebook-button.component.css │ │ │ │ │ ├── facebook-button.component.ts │ │ │ │ │ └── facebook-button.component.html │ │ │ ├── login │ │ │ │ ├── login.component.ts │ │ │ │ └── login.component.html │ │ │ └── sign-up │ │ │ │ ├── sign-up.component.ts │ │ │ │ └── sign-up.component.html │ │ ├── product-details │ │ │ ├── product-details.component.css │ │ │ └── product-details.component.ts │ │ ├── footer │ │ │ ├── footer.component.css │ │ │ ├── footer.component.ts │ │ │ └── footer.component.html │ │ ├── up-to-top │ │ │ ├── up-to-top.component.css │ │ │ ├── up-to-top.component.html │ │ │ └── up-to-top.component.ts │ │ ├── notfound-page │ │ │ ├── notfound-page.component.html │ │ │ ├── notfound-page.component.ts │ │ │ └── notfound-page.component.css │ │ ├── about │ │ │ ├── about.component.ts │ │ │ └── about.component.css │ │ ├── footer-upper │ │ │ ├── footer-upper.component.css │ │ │ ├── footer-upper.component.ts │ │ │ └── footer-upper.component.html │ │ ├── home │ │ │ ├── home.component.ts │ │ │ ├── home.component.css │ │ │ └── home.component.html │ │ ├── Payment │ │ │ ├── payment-fail │ │ │ │ ├── payment-fail.component.html │ │ │ │ ├── payment-fail.component.ts │ │ │ │ └── payment-fail.component.css │ │ │ ├── payment-success │ │ │ │ ├── payment-success.component.html │ │ │ │ ├── payment-success.component.ts │ │ │ │ └── payment-success.component.css │ │ │ ├── checkout │ │ │ │ ├── checkout.component.ts │ │ │ │ └── checkout.component.html │ │ │ └── payment-method │ │ │ │ ├── payment-method.component.ts │ │ │ │ └── payment-method.component.html │ │ ├── forget-password │ │ │ ├── forget-password.component.html │ │ │ ├── forget-password.component.ts │ │ │ └── forget-password.component.css │ │ ├── otp │ │ │ ├── otp.component.html │ │ │ ├── otp.component.ts │ │ │ └── otp.component.css │ │ ├── nav-bar │ │ │ ├── nav-bar.component.css │ │ │ ├── nav-bar.component.ts │ │ │ └── nav-bar.component.html │ │ ├── reset-password │ │ │ ├── reset-password.component.html │ │ │ ├── reset-password.component.ts │ │ │ └── reset-password.component.css │ │ └── main-page-items-section │ │ │ ├── main-page-items-section.component.ts │ │ │ ├── main-page-items-section.component.css │ │ │ └── main-page-items-section.component.html │ ├── app.component.html │ ├── Service │ │ ├── toast-service.service.ts │ │ ├── forget-password.service.ts │ │ ├── otp.service.ts │ │ ├── reset-password.service.ts │ │ ├── create-bid.service.ts │ │ ├── checkout.service.ts │ │ ├── dashboard-table.service.ts │ │ ├── bids.service.ts │ │ ├── auth.service.ts │ │ ├── profile-page.service.ts │ │ └── user-home-data.service.ts │ ├── Directives │ │ └── a-hover.directive.ts │ ├── intercreptors │ │ ├── auth.interceptor.ts │ │ └── response.interceptor.ts │ ├── core │ │ └── guards │ │ │ ├── auth.guard.ts │ │ │ ├── admin-auth.guard.ts │ │ │ └── guest-auth.guard.ts │ ├── app.component.ts │ ├── app-routing.module.ts │ └── icons │ │ └── icon-subset.ts ├── scss │ ├── _custom.scss │ ├── _charts.scss │ ├── _layout.scss │ ├── _fixes.scss │ ├── styles.scss │ ├── _scrollbar.scss │ └── _examples.scss ├── favicon.ico ├── Environment │ └── env.ts ├── main.ts ├── styles.css └── index.html ├── remoteconfig.template.json ├── .vscode ├── settings.json ├── extensions.json ├── launch.json └── tasks.json ├── .firebaserc ├── database.rules.json ├── .editorconfig ├── tsconfig.app.json ├── tsconfig.spec.json ├── .github └── workflows │ ├── firebase-hosting-merge.yml │ └── firebase-hosting-pull-request.yml ├── .gitignore ├── firebase.json ├── tsconfig.json ├── package.json ├── README.md └── angular.json /src/assets/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /remoteconfig.template.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /src/app/app.component.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | } 3 | -------------------------------------------------------------------------------- /src/app/Components/layout/layout.component.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/app/Components/mytoast/mytoast.component.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/app/Components/offcanvas/offcanvas.component.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/app/Components/Profile/bids/bids.component.css: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/app/Components/bid-history/bid-history.component.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/app/Components/dashboard/views/bids/bids.component.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/app/Components/footer-lower/footer-lower.component.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/app/Components/login-modal/login-modal.component.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/app/Components/Profile/apartments/apartments.component.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/app/Components/Profile/orders/orders.component.css: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/app/Components/dashboard/views/charts/charts.component.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/app/Components/login-modal/login-modal.component.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/scss/_custom.scss: -------------------------------------------------------------------------------- 1 | // Here you can add other styles 2 | 3 | -------------------------------------------------------------------------------- /src/app/Components/category-scroller/category-scroller.component.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/app/Components/edit-product-form/edit-product-form.component.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/app/Components/footer-column/footer-column.component.css: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/app/Components/category-scroller/category-scroller.component.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/app/Components/create-product-form/create-product-form.component.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.firebaserc: -------------------------------------------------------------------------------- 1 | { 2 | "projects": { 3 | "default": "agora-4" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /src/app/Components/dashboard/views/dashboard-users/dashboard-users.component.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/app/Components/Auth/thirdPartyLoginButtons/google-button/google-button.component.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/app/Components/dashboard/containers/index.ts: -------------------------------------------------------------------------------- 1 | export * from './default-layout'; 2 | -------------------------------------------------------------------------------- /src/app/Components/Auth/thirdPartyLoginButtons/facebook-button/facebook-button.component.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/app/Components/dashboard/views/dashboard-bid-details/dashboard-bid-details.component.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mohamedyousef44/Agoura-Angular/HEAD/src/favicon.ico -------------------------------------------------------------------------------- /src/app/Components/dashboard/containers/default-layout/default-footer/default-footer.component.scss: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/app/Components/dashboard/containers/default-layout/default-header/default-header.component.scss: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/imgs/default.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mohamedyousef44/Agoura-Angular/HEAD/src/assets/imgs/default.jpg -------------------------------------------------------------------------------- /src/assets/imgs/home/h1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mohamedyousef44/Agoura-Angular/HEAD/src/assets/imgs/home/h1.png -------------------------------------------------------------------------------- /src/assets/imgs/home/h2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mohamedyousef44/Agoura-Angular/HEAD/src/assets/imgs/home/h2.jpg -------------------------------------------------------------------------------- /src/assets/photos/Agoura.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mohamedyousef44/Agoura-Angular/HEAD/src/assets/photos/Agoura.png -------------------------------------------------------------------------------- /src/assets/photos/verify.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mohamedyousef44/Agoura-Angular/HEAD/src/assets/photos/verify.jpg -------------------------------------------------------------------------------- /src/assets/images/Visa.svg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mohamedyousef44/Agoura-Angular/HEAD/src/assets/images/Visa.svg.png -------------------------------------------------------------------------------- /src/assets/images/sgin_up.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mohamedyousef44/Agoura-Angular/HEAD/src/assets/images/sgin_up.jpg -------------------------------------------------------------------------------- /src/assets/imgs/home/image.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mohamedyousef44/Agoura-Angular/HEAD/src/assets/imgs/home/image.jpg -------------------------------------------------------------------------------- /src/assets/photos/avatar02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mohamedyousef44/Agoura-Angular/HEAD/src/assets/photos/avatar02.png -------------------------------------------------------------------------------- /src/assets/photos/mostafaa.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mohamedyousef44/Agoura-Angular/HEAD/src/assets/photos/mostafaa.jpeg -------------------------------------------------------------------------------- /src/assets/photos/omar-1.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mohamedyousef44/Agoura-Angular/HEAD/src/assets/photos/omar-1.jpeg -------------------------------------------------------------------------------- /src/assets/images/Google-Icon.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mohamedyousef44/Agoura-Angular/HEAD/src/assets/images/Google-Icon.jpg -------------------------------------------------------------------------------- /src/assets/images/not-default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mohamedyousef44/Agoura-Angular/HEAD/src/assets/images/not-default.png -------------------------------------------------------------------------------- /src/assets/images/login_london.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mohamedyousef44/Agoura-Angular/HEAD/src/assets/images/login_london.jpg -------------------------------------------------------------------------------- /src/app/Components/edit-product-form/edit-product-form.component.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/assets/images/MasterCard_Logo.svg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mohamedyousef44/Agoura-Angular/HEAD/src/assets/images/MasterCard_Logo.svg.png -------------------------------------------------------------------------------- /src/assets/images/icons8-facebook-48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mohamedyousef44/Agoura-Angular/HEAD/src/assets/images/icons8-facebook-48.png -------------------------------------------------------------------------------- /src/assets/images/icons8-apple-logo-50.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mohamedyousef44/Agoura-Angular/HEAD/src/assets/images/icons8-apple-logo-50.png -------------------------------------------------------------------------------- /src/app/Components/Auth/thirdPartyLoginButtons/google-button/google-button.component.html: -------------------------------------------------------------------------------- 1 | 2 |
3 | -------------------------------------------------------------------------------- /src/Environment/env.ts: -------------------------------------------------------------------------------- 1 | export const Environment = { 2 | 3 | apiUrl: 'https://agora-node-server.onrender.com' 4 | // apiUrl: 'http://localhost:9000' 5 | }; 6 | -------------------------------------------------------------------------------- /src/app/Components/product-details/product-details.component.css: -------------------------------------------------------------------------------- 1 | .pointer{ 2 | cursor: pointer; 3 | } 4 | .thumbnails img:hover{ 5 | opacity: .8; 6 | } 7 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=827846 3 | "recommendations": ["angular.ng-template"] 4 | } 5 | -------------------------------------------------------------------------------- /src/app/Components/footer/footer.component.css: -------------------------------------------------------------------------------- 1 | app-footer-lower a{ 2 | color:#6B6B6B; 3 | font-size: 1.5rem; 4 | } 5 | app-footer-lower a:hover{ 6 | transform: scale(1.1); 7 | } 8 | -------------------------------------------------------------------------------- /src/app/app.component.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/app/Components/up-to-top/up-to-top.component.css: -------------------------------------------------------------------------------- 1 | .fixed{ 2 | position: fixed; 3 | bottom: 20px; 4 | right: 20px; 5 | } 6 | 7 | .btn-color{ 8 | background-color: #46756F; 9 | } 10 | -------------------------------------------------------------------------------- /database.rules.json: -------------------------------------------------------------------------------- 1 | { 2 | /* Visit https://firebase.google.com/docs/database/security to learn more about security rules. */ 3 | "rules": { 4 | ".read": false, 5 | ".write": false 6 | } 7 | } -------------------------------------------------------------------------------- /src/scss/_charts.scss: -------------------------------------------------------------------------------- 1 | // temp fix .chartjs-tooltip-body-item 2 | 3 | .chartjs-tooltip-body-item > td { 4 | padding-bottom: 0 !important; 5 | padding-top: 0 !important; 6 | font-size: smaller; 7 | } 8 | -------------------------------------------------------------------------------- /src/app/Components/dashboard/containers/default-layout/index.ts: -------------------------------------------------------------------------------- 1 | export * from './default-footer/default-footer.component'; 2 | export * from './default-header/default-header.component'; 3 | export * from './default-layout.component'; 4 | -------------------------------------------------------------------------------- /src/app/Components/notfound-page/notfound-page.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |

Error 404

4 |

Go backGo back home....

5 |
6 |
7 | -------------------------------------------------------------------------------- /src/app/Components/footer-column/footer-column.component.html: -------------------------------------------------------------------------------- 1 |
2 |
{{ text | uppercase }}
3 |
4 | 5 |
6 |
7 | -------------------------------------------------------------------------------- /src/scss/_layout.scss: -------------------------------------------------------------------------------- 1 | .wrapper { 2 | width: 100%; 3 | @include ltr-rtl("padding-left", var(--cui-sidebar-occupy-start, 0)); 4 | @include ltr-rtl("padding-right", var(--cui-sidebar-occupy-end, 0)); 5 | will-change: auto; 6 | @include transition(padding .15s); 7 | } 8 | -------------------------------------------------------------------------------- /src/app/Components/about/about.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-about', 5 | templateUrl: './about.component.html', 6 | styleUrls: ['./about.component.css'] 7 | }) 8 | export class AboutComponent { 9 | 10 | } 11 | -------------------------------------------------------------------------------- /src/app/Components/footer/footer.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-footer', 5 | templateUrl: './footer.component.html', 6 | styleUrls: ['./footer.component.css'] 7 | }) 8 | export class FooterComponent { 9 | 10 | } 11 | -------------------------------------------------------------------------------- /src/app/Components/footer-lower/footer-lower.component.html: -------------------------------------------------------------------------------- 1 |
2 |

{{ text }}

3 |
4 | 5 |
6 |
7 | -------------------------------------------------------------------------------- /src/app/Components/footer-upper/footer-upper.component.css: -------------------------------------------------------------------------------- 1 | app-footer-column a{ 2 | text-decoration: none; 3 | color: #FFFCF5; 4 | padding-top: 1rem; 5 | } 6 | app-footer-column a:hover{ 7 | text-decoration: underline; 8 | } 9 | 10 | .footer-bg{ 11 | background-color: #252B60; 12 | } 13 | -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 4 | 5 | import { AppModule } from './app/app.module'; 6 | 7 | 8 | platformBrowserDynamic().bootstrapModule(AppModule) 9 | .catch(err => console.error(err)); 10 | -------------------------------------------------------------------------------- /src/app/Components/up-to-top/up-to-top.component.html: -------------------------------------------------------------------------------- 1 |
5 | 8 |

{{ style }}

9 |
10 | -------------------------------------------------------------------------------- /src/app/Components/footer-upper/footer-upper.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-footer-upper', 5 | templateUrl: './footer-upper.component.html', 6 | styleUrls: ['./footer-upper.component.css'] 7 | }) 8 | export class FooterUpperComponent { 9 | 10 | } 11 | -------------------------------------------------------------------------------- /src/app/Components/notfound-page/notfound-page.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-notfound-page', 5 | templateUrl: './notfound-page.component.html', 6 | styleUrls: ['./notfound-page.component.css'] 7 | }) 8 | export class NotfoundPageComponent { 9 | 10 | } 11 | -------------------------------------------------------------------------------- /src/scss/_fixes.scss: -------------------------------------------------------------------------------- 1 | // Place for temp fixes 2 | 3 | .form-floating > .form-select { 4 | padding-top: 1.625rem !important; 5 | padding-bottom: 0.625rem !important; 6 | } 7 | 8 | // temp fix for scrollbar styling (wip) 9 | @import "scrollbar"; 10 | 11 | // temp fix .chartjs-tooltip-body-item padding 12 | @import "charts"; 13 | -------------------------------------------------------------------------------- /src/app/Components/edit-product-form/edit-product-form.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-edit-product-form', 5 | templateUrl: './edit-product-form.component.html', 6 | styleUrls: ['./edit-product-form.component.css'] 7 | }) 8 | export class EditProductFormComponent { 9 | 10 | } 11 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see https://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.ts] 12 | quote_type = single 13 | 14 | [*.md] 15 | max_line_length = off 16 | trim_trailing_whitespace = false 17 | -------------------------------------------------------------------------------- /src/app/Components/footer-lower/footer-lower.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, Input } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-footer-lower', 5 | templateUrl: './footer-lower.component.html', 6 | styleUrls: ['./footer-lower.component.css'] 7 | }) 8 | export class FooterLowerComponent { 9 | @Input('text') text: any 10 | } 11 | -------------------------------------------------------------------------------- /src/app/Components/login-modal/login-modal.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-login-modal', 5 | templateUrl: './login-modal.component.html', 6 | styleUrls: ['./login-modal.component.css'] 7 | }) 8 | export class LoginModalComponent { 9 | 10 | onClose(){ 11 | 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /src/app/Components/dashboard/containers/default-layout/default-footer/default-footer.component.html: -------------------------------------------------------------------------------- 1 | 2 |
3 | Agora 4 | © 2023 Copy rights 5 |
6 |
7 | Powered by 8 | 9 | Agora 10 | 11 |
12 | 13 | -------------------------------------------------------------------------------- /tsconfig.app.json: -------------------------------------------------------------------------------- 1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */ 2 | { 3 | "extends": "./tsconfig.json", 4 | "compilerOptions": { 5 | "outDir": "./out-tsc/app", 6 | "types": [ 7 | "@angular/localize" 8 | ] 9 | }, 10 | "files": [ 11 | "src/main.ts" 12 | ], 13 | "include": [ 14 | "src/**/*.d.ts" 15 | ], 16 | } 17 | -------------------------------------------------------------------------------- /src/app/Components/home/home.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit, SimpleChange } from '@angular/core'; 2 | import { UserHomeDataService } from 'src/app/Service/user-home-data.service'; 3 | 4 | @Component({ 5 | selector: 'app-home', 6 | templateUrl: './home.component.html', 7 | styleUrls: ['./home.component.css'] 8 | }) 9 | export class HomeComponent { 10 | 11 | 12 | } 13 | -------------------------------------------------------------------------------- /tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */ 2 | { 3 | "extends": "./tsconfig.json", 4 | "compilerOptions": { 5 | "outDir": "./out-tsc/spec", 6 | "types": [ 7 | "jasmine", 8 | "@angular/localize" 9 | ] 10 | }, 11 | "include": [ 12 | "src/**/*.spec.ts", 13 | "src/**/*.d.ts" 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /src/app/Components/home/home.component.css: -------------------------------------------------------------------------------- 1 | .cus-bg-img { 2 | background-image: url("/assets/imgs/home/image.jpg"); 3 | background-size: cover; 4 | min-height: 100vh; 5 | position: relative; 6 | } 7 | .word-container{ 8 | height: 80% !important; 9 | } 10 | .word-container p{ 11 | color:rgb(255,250,250); 12 | font-size: 400%; 13 | font-weight: bolder; 14 | user-select: none; 15 | } 16 | -------------------------------------------------------------------------------- /src/app/Components/footer-column/footer-column.component.ts: -------------------------------------------------------------------------------- 1 | import { AfterViewInit, Component, Input, ViewChild, ViewChildren } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-footer-column', 5 | templateUrl: './footer-column.component.html', 6 | styleUrls: ['./footer-column.component.css'] 7 | }) 8 | export class FooterColumnComponent { 9 | 10 | @Input('headline') text: any 11 | 12 | } 13 | -------------------------------------------------------------------------------- /src/app/Components/Auth/thirdPartyLoginButtons/facebook-button/facebook-button.component.ts: -------------------------------------------------------------------------------- 1 | 2 | import { Component, OnInit } from '@angular/core'; 3 | 4 | @Component({ 5 | selector: 'app-facebook-button', 6 | templateUrl: './facebook-button.component.html', 7 | styleUrls: ['./facebook-button.component.css'] 8 | }) 9 | export class FacebookButtonComponent{ 10 | user: any; 11 | loggedIn: any; 12 | 13 | } 14 | -------------------------------------------------------------------------------- /src/app/Components/footer/footer.component.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | -------------------------------------------------------------------------------- /src/app/Components/category-scroller/category-scroller.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-category-scroller', 5 | templateUrl: './category-scroller.component.html', 6 | styleUrls: ['./category-scroller.component.css'], 7 | }) 8 | export class CategoryScrollerComponent { 9 | 10 | luxurious:any; 11 | studio:any; 12 | villa:any 13 | palace:any 14 | 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/app/Service/toast-service.service.ts: -------------------------------------------------------------------------------- 1 | import { EventEmitter, Injectable } from '@angular/core'; 2 | 3 | @Injectable({ 4 | providedIn: 'root' 5 | }) 6 | export class ToastService { 7 | 8 | constructor() { } 9 | public toastEvent: EventEmitter = new EventEmitter(); 10 | 11 | activateToast(message: string,success:boolean) { 12 | let data={message,success} 13 | this.toastEvent.emit(JSON.stringify(data)); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/app/Components/mytoast/mytoast.component.ts: -------------------------------------------------------------------------------- 1 | import { Input,Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-mytoast', 5 | templateUrl: './mytoast.component.html', 6 | styleUrls: ['./mytoast.component.css'], 7 | 8 | }) 9 | export class MytoastComponent { 10 | @Input("visible") visible = false; 11 | @Input("title") title = ''; 12 | @Input("success") success =true; 13 | 14 | position = 'top-end'; 15 | 16 | 17 | 18 | } -------------------------------------------------------------------------------- /src/app/Components/dashboard/containers/default-layout/default-footer/default-footer.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | import { FooterComponent } from '@coreui/angular'; 3 | 4 | @Component({ 5 | selector: 'app-default-footer', 6 | templateUrl: './default-footer.component.html', 7 | styleUrls: ['./default-footer.component.scss'], 8 | }) 9 | export class DefaultFooterComponent extends FooterComponent { 10 | constructor() { 11 | super(); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/app/Service/forget-password.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { HttpClient } from '@angular/common/http'; 3 | import {Environment} from "../../Environment/env" 4 | 5 | @Injectable({ 6 | providedIn: 'root' 7 | }) 8 | export class ForgetPasswordService { 9 | private apiUrl = Environment.apiUrl+'/api'; 10 | 11 | constructor(private http: HttpClient) {} 12 | 13 | sendOTP(email: string) { 14 | return this.http.post(`${this.apiUrl}/sendOTP`, { email }); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/app/Components/Auth/thirdPartyLoginButtons/facebook-button/facebook-button.component.html: -------------------------------------------------------------------------------- 1 | 12 | Facebook sign-in 18 | Continue with Facebook 19 | 20 | -------------------------------------------------------------------------------- /src/app/Service/otp.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { HttpClient } from '@angular/common/http'; 3 | import {Environment} from "../../Environment/env" 4 | 5 | @Injectable({ 6 | providedIn: 'root' 7 | }) 8 | export class OtpService { 9 | private apiUrl = Environment.apiUrl+'/api'; // Update the base URL 10 | 11 | constructor(private http: HttpClient) {} 12 | 13 | verifyOTP(otp: string) { 14 | return this.http.post<{ resetToken: string }>(`${this.apiUrl}/verifyOTP`, { otp }); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/app/Components/Payment/payment-fail/payment-fail.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 | 6 |

Your payment failed

7 |

Try again later

8 |

redirecting back in... {{timer}}

9 |
10 |
11 |
12 |
-------------------------------------------------------------------------------- /src/app/Components/layout/layout.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |

Loading...

18 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 3 | "version": "0.2.0", 4 | "configurations": [ 5 | { 6 | "name": "ng serve", 7 | "type": "pwa-chrome", 8 | "request": "launch", 9 | "preLaunchTask": "npm: start", 10 | "url": "http://localhost:4200/" 11 | }, 12 | { 13 | "name": "ng test", 14 | "type": "chrome", 15 | "request": "launch", 16 | "preLaunchTask": "npm: test", 17 | "url": "http://localhost:9876/debug.html" 18 | } 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /src/app/Service/reset-password.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { HttpClient } from '@angular/common/http'; 3 | import {Environment} from "../../Environment/env" 4 | 5 | @Injectable({ 6 | providedIn: 'root' 7 | }) 8 | export class ResetPasswordService { 9 | private apiUrl = Environment.apiUrl+'/api'; // Update the base URL 10 | 11 | constructor(private http: HttpClient) {} 12 | 13 | resetPassword(resetToken: string, newPassword: string) { 14 | return this.http.post(`${this.apiUrl}/resetPassword`, { resetToken, newPassword }); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/app/Service/create-bid.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { HttpClient, HttpHeaders } from '@angular/common/http'; 3 | import {Environment} from "../../Environment/env" 4 | 5 | @Injectable({ 6 | providedIn: 'root' 7 | }) 8 | export class CreateBidService { 9 | private readonly Base_URL = Environment.apiUrl; 10 | private headers=new HttpHeaders({'content-type': 'multipart/form-data'}); 11 | constructor(private myClient:HttpClient) { 12 | 13 | } 14 | post(bid:any){ 15 | return this.myClient.post(`${this.Base_URL}/place/create`,bid) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/styles.css: -------------------------------------------------------------------------------- 1 | /* You can add global styles to this file, and also import other style files */ 2 | 3 | 4 | html, body { height: 100%; } 5 | body { margin: 0; font-family: Roboto, "Helvetica Neue", sans-serif; } 6 | 7 | .bid-shadow{ 8 | -webkit-box-shadow: 5px 10px 5px -1px rgba(0,0,0,0.75); 9 | -moz-box-shadow: 5px 10px 5px -1px rgba(0,0,0,0.75); 10 | box-shadow: 5px 10px 5px -1px rgba(0,0,0,0.75); 11 | margin: 5% 0; 12 | min-height: 100px; 13 | display: flex; 14 | flex-direction: column; 15 | justify-content: space-between; 16 | align-items: center; 17 | padding: 5%; 18 | } 19 | -------------------------------------------------------------------------------- /src/app/Components/Payment/payment-success/payment-success.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 | 6 |

Your payment was successful

7 |

Thank you for your payment. we will
8 | be in contact with more details shortly

9 |

redirecting back in... {{timer}}

10 |
11 |
12 |
13 |
-------------------------------------------------------------------------------- /src/app/Components/forget-password/forget-password.component.html: -------------------------------------------------------------------------------- 1 |
2 |

Forget Password

3 |

Please enter your email address below
and we will send you a link to reset your password.

4 |
5 | 6 | 7 | 8 |
9 |
10 | -------------------------------------------------------------------------------- /src/app/Components/notfound-page/notfound-page.component.css: -------------------------------------------------------------------------------- 1 | #main{ 2 | display: table; 3 | width: 100%; 4 | height: 100vh; 5 | background-image: url("/assets/imgs/home/h1.png"); 6 | background-size: cover; 7 | 8 | text-align: center; 9 | } 10 | 11 | .fof{ 12 | display: table-cell; 13 | vertical-align: middle; 14 | } 15 | 16 | .fof h1{ 17 | font-size: 50px; 18 | display: inline-block; 19 | padding-right: 12px; 20 | animation: type .5s alternate infinite; 21 | } 22 | 23 | @keyframes type{ 24 | from{box-shadow: inset -3px 0px 0px #888;} 25 | to{box-shadow: inset -3px 0px 0px transparent;} 26 | } 27 | -------------------------------------------------------------------------------- /src/app/Directives/a-hover.directive.ts: -------------------------------------------------------------------------------- 1 | import { Directive, ElementRef, HostListener, Input, Renderer2 } from '@angular/core'; 2 | 3 | @Directive({ 4 | selector: '[appAHover]' 5 | }) 6 | export class AHoverDirective { 7 | 8 | @Input('appAHover') className: any 9 | 10 | @HostListener('mouseover') onMouseOver(){ 11 | this.render.addClass(this.el.nativeElement , this.className) 12 | } 13 | @HostListener('mouseover') onMouseOut(){ 14 | this.render.removeClass(this.el.nativeElement , this.className) 15 | } 16 | 17 | constructor(private el: ElementRef , private render: Renderer2) { 18 | 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/app/Components/dashboard/containers/default-layout/_nav.ts: -------------------------------------------------------------------------------- 1 | import { INavData } from '@coreui/angular'; 2 | 3 | export const navItems: INavData[] = [ 4 | { 5 | name: 'Dashboard', 6 | url: '/dashboard', 7 | iconComponent: { name: 'cil-speedometer' }, 8 | }, 9 | { 10 | name: 'users', 11 | url: './users', 12 | iconComponent: { name: 'cil-user' }, 13 | }, 14 | { 15 | name: 'apartments', 16 | url: './apartments', 17 | iconComponent: { name: 'cil-home' }, 18 | }, 19 | { 20 | name: 'Charts', 21 | url: './charts', 22 | iconComponent: { name: 'cil-chart-pie' } 23 | }, 24 | ]; 25 | -------------------------------------------------------------------------------- /src/app/Service/checkout.service.ts: -------------------------------------------------------------------------------- 1 | import { HttpClient } from '@angular/common/http'; 2 | import { Injectable } from '@angular/core'; 3 | import {Environment} from "../../Environment/env" 4 | 5 | @Injectable({ 6 | providedIn: 'root' 7 | }) 8 | export class CheckoutService { 9 | private readonly Base_URL = Environment.apiUrl; 10 | 11 | constructor(private myClient:HttpClient) { 12 | 13 | } 14 | 15 | getOrderDetails(id:any){ 16 | return this.myClient.get(`${this.Base_URL}/checkout/${id}`) 17 | } 18 | checkout(id:any,data:any){ 19 | return this.myClient.post(`${this.Base_URL}/checkout/${id}`,data) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/app/Components/Payment/payment-fail/payment-fail.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | import { Router } from '@angular/router'; 3 | 4 | @Component({ 5 | selector: 'app-payment-fail', 6 | templateUrl: './payment-fail.component.html', 7 | styleUrls: ['./payment-fail.component.css'] 8 | }) 9 | export class PaymentFailComponent { 10 | timer=5; 11 | constructor(private router:Router){ 12 | let interval=setInterval(()=>{ 13 | if(this.timer==0){ 14 | clearInterval(interval) 15 | this.router.navigateByUrl("/home") 16 | 17 | } 18 | --this.timer; 19 | },1000) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/app/Components/otp/otp.component.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
OTP Verification
4 |

Please enter the code sent to you by email.

5 |
6 |
7 | 8 |
9 |
10 | 11 |
12 |
13 |
14 | 15 | -------------------------------------------------------------------------------- /src/app/Components/Payment/payment-success/payment-success.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | import { Router } from '@angular/router'; 3 | 4 | @Component({ 5 | selector: 'app-payment-success', 6 | templateUrl: './payment-success.component.html', 7 | styleUrls: ['./payment-success.component.css'] 8 | }) 9 | export class PaymentSuccessComponent { 10 | timer=5; 11 | constructor(private router:Router){ 12 | let interval=setInterval(()=>{ 13 | if(this.timer==0){ 14 | clearInterval(interval) 15 | this.router.navigateByUrl("/home") 16 | 17 | } 18 | --this.timer; 19 | },1000) 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/app/intercreptors/auth.interceptor.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { HttpHandler, HttpEvent, HttpInterceptor, HttpRequest } from '@angular/common/http'; 3 | import { Observable } from 'rxjs'; 4 | 5 | @Injectable({providedIn: 'root'}) 6 | export class AuthInterceptor implements HttpInterceptor { 7 | 8 | constructor() {} 9 | 10 | intercept(req: HttpRequest, next: HttpHandler): Observable>{ 11 | 12 | const token = localStorage.getItem('X-Auth-Token') 13 | 14 | return next.handle(req.clone({ 15 | setHeaders: { 16 | Authorization: `${token}` 17 | } 18 | })); 19 | 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/app/Components/dashboard/views/charts/charts.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |

User per year

4 | 8 | 9 | 10 |
11 | 12 |

Bids per year

13 | 14 | 15 |
16 | 17 |

Apartments status

18 | 19 |
20 |
21 | 22 | -------------------------------------------------------------------------------- /src/app/core/guards/auth.guard.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { ActivatedRouteSnapshot, CanActivate, RouterStateSnapshot, UrlTree } from '@angular/router'; 3 | import { Observable } from 'rxjs'; 4 | 5 | @Injectable({ 6 | providedIn: 'root' 7 | }) 8 | export class AuthGuard implements CanActivate { 9 | constructor(){} 10 | canActivate( 11 | route: ActivatedRouteSnapshot, 12 | state: RouterStateSnapshot): Observable | Promise | boolean | UrlTree { 13 | console.log({route , state}) 14 | if(!localStorage.getItem('X-Auth-Token')){ 15 | return false; 16 | } 17 | return true; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /.github/workflows/firebase-hosting-merge.yml: -------------------------------------------------------------------------------- 1 | # This file was auto-generated by the Firebase CLI 2 | # https://github.com/firebase/firebase-tools 3 | 4 | name: Deploy to Firebase Hosting on merge 5 | 'on': 6 | push: 7 | branches: 8 | - main 9 | jobs: 10 | build_and_deploy: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v3 14 | - run: npm ci && npm run build 15 | - uses: FirebaseExtended/action-hosting-deploy@v0 16 | with: 17 | repoToken: '${{ secrets.GITHUB_TOKEN }}' 18 | firebaseServiceAccount: '${{ secrets.FIREBASE_SERVICE_ACCOUNT_AGORA_4 }}' 19 | channelId: live 20 | projectId: agora-4 21 | -------------------------------------------------------------------------------- /src/app/Components/mytoast/mytoast.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 |
6 |
7 |
8 |

{{title}}

9 |
10 |
11 |
12 |
13 | -------------------------------------------------------------------------------- /src/app/Components/nav-bar/nav-bar.component.css: -------------------------------------------------------------------------------- 1 | 2 | .a-hover:hover{ 3 | background-color: #B0B1AB; 4 | } 5 | 6 | .b-hover:hover{ 7 | border-bottom: 2px #000000 solid; 8 | } 9 | 10 | .badge-position{ 11 | top: 30%; 12 | left: 90%; 13 | font-size: .8rem; 14 | 15 | } 16 | .b-hover-dark:hover{ 17 | border-bottom: 2px #000000 solid; 18 | } 19 | .img-hover:hover{ 20 | border:5px #000000 solid; 21 | opacity: .6; 22 | box-shadow: 0px 0px 3px 2px lightblue; 23 | transition: .3s; 24 | } 25 | 26 | .nav-pos{ 27 | position: fixed; 28 | z-index: 100; 29 | } 30 | 31 | .nav-scrolled{ 32 | background-color: rgba(0, 0, 0, 0.5) !important; 33 | } 34 | .nav-scrolled i{ 35 | color:white !important; 36 | } 37 | -------------------------------------------------------------------------------- /.github/workflows/firebase-hosting-pull-request.yml: -------------------------------------------------------------------------------- 1 | # This file was auto-generated by the Firebase CLI 2 | # https://github.com/firebase/firebase-tools 3 | 4 | name: Deploy to Firebase Hosting on PR 5 | 'on': pull_request 6 | jobs: 7 | build_and_preview: 8 | if: '${{ github.event.pull_request.head.repo.full_name == github.repository }}' 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v3 12 | - run: npm ci && npm run build 13 | - uses: FirebaseExtended/action-hosting-deploy@v0 14 | with: 15 | repoToken: '${{ secrets.GITHUB_TOKEN }}' 16 | firebaseServiceAccount: '${{ secrets.FIREBASE_SERVICE_ACCOUNT_AGORA_4 }}' 17 | projectId: agora-4 18 | -------------------------------------------------------------------------------- /src/app/Components/dashboard/views/bids/bids.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | import { DashboardTableService } from 'src/app/Service/dashboard-table.service'; 3 | 4 | @Component({ 5 | selector: 'app-bids', 6 | templateUrl: './bids.component.html', 7 | styleUrls: ['./bids.component.css'] 8 | }) 9 | export class BidsComponent { 10 | allAppartments:any 11 | constructor(public myService:DashboardTableService){} 12 | ngOnInit(): void { 13 | this.myService.GetAllAppartment().subscribe( 14 | { 15 | next:(data: any)=>{ 16 | console.log(data[1]); 17 | this.allAppartments=data; 18 | }, 19 | error:(err: any)=>{console.log(err)} 20 | } 21 | ) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # Compiled output 4 | /dist 5 | /tmp 6 | /out-tsc 7 | /bazel-out 8 | 9 | # Node 10 | /node_modules 11 | npm-debug.log 12 | yarn-error.log 13 | 14 | # IDEs and editors 15 | .idea/ 16 | .project 17 | .classpath 18 | .c9/ 19 | *.launch 20 | .settings/ 21 | *.sublime-workspace 22 | 23 | # Visual Studio Code 24 | .vscode/* 25 | !.vscode/settings.json 26 | !.vscode/tasks.json 27 | !.vscode/launch.json 28 | !.vscode/extensions.json 29 | .history/* 30 | 31 | # Miscellaneous 32 | /.angular/cache 33 | .sass-cache/ 34 | /connect.lock 35 | /coverage 36 | /libpeerconnection.log 37 | testem.log 38 | /typings 39 | 40 | # System files 41 | .DS_Store 42 | Thumbs.db 43 | -------------------------------------------------------------------------------- /src/app/Components/Payment/payment-fail/payment-fail.component.css: -------------------------------------------------------------------------------- 1 | ._failed{ border-bottom: solid 4px red !important; } 2 | ._failed i{ color:red !important; } 3 | 4 | ._success { 5 | box-shadow: 0 15px 25px #00000019; 6 | padding: 45px; 7 | width: 100%; 8 | text-align: center; 9 | margin: 40px auto; 10 | border-bottom: solid 4px #28a745; 11 | } 12 | 13 | ._success i { 14 | font-size: 55px; 15 | color: #28a745; 16 | } 17 | 18 | ._success h2 { 19 | margin-bottom: 12px; 20 | font-size: 40px; 21 | font-weight: 500; 22 | line-height: 1.2; 23 | margin-top: 10px; 24 | } 25 | 26 | ._success p { 27 | margin-bottom: 0px; 28 | font-size: 18px; 29 | color: #495057; 30 | font-weight: 500; 31 | } -------------------------------------------------------------------------------- /src/app/Components/dashboard/containers/default-layout/default-header/default-header.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, Input } from '@angular/core'; 2 | import { FormControl, FormGroup } from '@angular/forms'; 3 | 4 | import { ClassToggleService, HeaderComponent } from '@coreui/angular'; 5 | 6 | @Component({ 7 | selector: 'app-default-header', 8 | templateUrl: './default-header.component.html', 9 | }) 10 | export class DefaultHeaderComponent extends HeaderComponent { 11 | 12 | @Input() sidebarId: string = "sidebar"; 13 | 14 | public newMessages = new Array(4) 15 | public newTasks = new Array(5) 16 | public newNotifications = new Array(5) 17 | 18 | constructor(private classToggler: ClassToggleService) { 19 | super(); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/app/Components/Payment/payment-success/payment-success.component.css: -------------------------------------------------------------------------------- 1 | ._failed{ border-bottom: solid 4px red !important; } 2 | ._failed i{ color:red !important; } 3 | 4 | ._success { 5 | box-shadow: 0 15px 25px #00000019; 6 | padding: 45px; 7 | width: 100%; 8 | text-align: center; 9 | margin: 40px auto; 10 | border-bottom: solid 4px #28a745; 11 | } 12 | 13 | ._success i { 14 | font-size: 55px; 15 | color: #28a745; 16 | } 17 | 18 | ._success h2 { 19 | margin-bottom: 12px; 20 | font-size: 40px; 21 | font-weight: 500; 22 | line-height: 1.2; 23 | margin-top: 10px; 24 | } 25 | 26 | ._success p { 27 | margin-bottom: 0px; 28 | font-size: 18px; 29 | color: #495057; 30 | font-weight: 500; 31 | } -------------------------------------------------------------------------------- /src/app/Components/home/home.component.html: -------------------------------------------------------------------------------- 1 |
2 |
5 |

6 | agora 7 |

8 |

11 | The Perfect 12 |

13 |

16 | Place For You 17 |

18 |
19 |
20 |
21 | 22 |
23 | -------------------------------------------------------------------------------- /src/scss/styles.scss: -------------------------------------------------------------------------------- 1 | /* You can add global styles to this file, and also import other style files */ 2 | // If you want to override variables do it here 3 | @import "variables"; 4 | 5 | $enable-ltr: true; 6 | $enable-rtl: true; 7 | 8 | // Import styles with default layout. 9 | @import "@coreui/coreui/scss/coreui"; 10 | 11 | // Import Chart.js custom tooltips styles 12 | @import "@coreui/chartjs/scss/coreui-chartjs"; 13 | 14 | // perfect scrollbar theming for use with [perfectScrollbar] directive 15 | //@import '~perfect-scrollbar/css/perfect-scrollbar.css'; 16 | 17 | @import "layout"; 18 | 19 | // Some temp fixes 20 | @import "fixes"; 21 | 22 | // Prism.js 23 | @import "examples"; 24 | 25 | // If you want to add something do it here 26 | @import "custom"; 27 | -------------------------------------------------------------------------------- /src/app/Components/reset-password/reset-password.component.html: -------------------------------------------------------------------------------- 1 |
2 |

Reset Password

3 |

Please enter a new password below.

4 |
5 | 6 | 7 | 8 | 9 | 10 |
11 |
12 | -------------------------------------------------------------------------------- /src/scss/_scrollbar.scss: -------------------------------------------------------------------------------- 1 | // scrollbar tinkering 2 | 3 | @supports (scrollbar-width: thin) { 4 | * { 5 | scrollbar-width: thin; 6 | scrollbar-color: #444 transparent; 7 | } 8 | } 9 | 10 | ::-webkit-scrollbar { 11 | width: .9em; 12 | } 13 | 14 | ::-webkit-scrollbar-track { 15 | background: var(--cui-body-bg, #fff); 16 | border-radius: 100vw; 17 | margin-block: .2em; 18 | } 19 | 20 | ::-webkit-scrollbar-thumb { 21 | background: #999; 22 | border: .2em solid var(--cui-body-bg, #fff); 23 | border-radius: 100vw; 24 | } 25 | 26 | ::-webkit-scrollbar-thumb:hover { 27 | background: #444; 28 | } 29 | 30 | .dark-theme::-webkit-scrollbar-thumb { 31 | background: #444; 32 | } 33 | 34 | .dark-theme::-webkit-scrollbar-thumb:hover { 35 | background: #999; 36 | } 37 | -------------------------------------------------------------------------------- /src/app/Components/up-to-top/up-to-top.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, HostListener, Input } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-up-to-top', 5 | templateUrl: './up-to-top.component.html', 6 | styleUrls: ['./up-to-top.component.css'] 7 | }) 8 | export class UpToTopComponent { 9 | 10 | showBtn = false 11 | 12 | @Input('position') style: any 13 | 14 | @HostListener('window:scroll', []) 15 | 16 | onWindowScroll(){ 17 | 18 | const scrollTop = document.documentElement.scrollTop || document.body.scrollTop; 19 | 20 | if(scrollTop > 400) { 21 | this.showBtn = true 22 | }else { 23 | this.showBtn = false 24 | } 25 | } 26 | 27 | toUp(){ 28 | window.scroll({ 29 | top:0, 30 | behavior: 'smooth' 31 | }) 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/app/core/guards/admin-auth.guard.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot, UrlTree } from '@angular/router'; 3 | import { Observable } from 'rxjs'; 4 | import { AuthService } from 'src/app/Service/auth.service'; 5 | 6 | @Injectable({ 7 | providedIn: 'root' 8 | }) 9 | export class AdminAuthGuard implements CanActivate { 10 | constructor(private authService:AuthService,private router:Router){} 11 | canActivate( 12 | route: ActivatedRouteSnapshot, 13 | state: RouterStateSnapshot): Observable | Promise | boolean | UrlTree { 14 | if(this.authService.verify()){ 15 | return true; 16 | } 17 | this.router.navigateByUrl("/404-notfound") 18 | return false; 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/app/core/guards/guest-auth.guard.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot, UrlTree } from '@angular/router'; 3 | import { Observable } from 'rxjs'; 4 | import { AuthService } from 'src/app/Service/auth.service'; 5 | 6 | @Injectable({ 7 | providedIn: 'root' 8 | }) 9 | export class GuestAuthGuard implements CanActivate { 10 | constructor(private authService:AuthService,private router:Router){} 11 | canActivate( 12 | route: ActivatedRouteSnapshot, 13 | state: RouterStateSnapshot): Observable | Promise | boolean | UrlTree { 14 | if(!localStorage.getItem("X-Auth-Token")){ 15 | return true; 16 | } 17 | this.router.navigateByUrl("/home") 18 | return false; 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/app/Service/dashboard-table.service.ts: -------------------------------------------------------------------------------- 1 | import { HttpClient } from '@angular/common/http'; 2 | import { Injectable } from '@angular/core'; 3 | import {Environment} from "../../Environment/env" 4 | 5 | @Injectable({ 6 | providedIn: 'root' 7 | }) 8 | export class DashboardTableService { 9 | private readonly Base_URL = Environment.apiUrl+"/dashboard"; 10 | constructor(private readonly myClient: HttpClient) { } 11 | 12 | GetAllAppartment() { 13 | return this.myClient.get(this.Base_URL + "/appartments" ); 14 | } 15 | GetAllCharts() { 16 | return this.myClient.get(this.Base_URL + "/charts" ); 17 | } 18 | 19 | GetAllUsers() { 20 | return this.myClient.get(this.Base_URL + "/allusers" ); 21 | } 22 | 23 | GetPlaceById(id: any) { 24 | return this.myClient.get(this.Base_URL + `/appartments/${id}`); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/app/Components/Profile/orders/orders.component.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 |

You Do Not Have Any Orders Till Now

5 |
6 |
7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 |
ApartmentBidDate
{{ order.apartment.title }}{{ order.amount }}{{ order.date }}
25 |
26 |
27 | -------------------------------------------------------------------------------- /src/app/Components/otp/otp.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | import { Router } from '@angular/router'; 3 | import { OtpService } from '../../Service/otp.service'; 4 | 5 | @Component({ 6 | selector: 'app-otp', 7 | templateUrl: './otp.component.html', 8 | styleUrls: ['./otp.component.css'] 9 | }) 10 | export class OtpComponent { 11 | otp: string= ''; 12 | resetToken: string = ''; 13 | 14 | constructor(private otpService: OtpService, private router: Router) {} 15 | 16 | onSubmit() { 17 | this.otpService.verifyOTP( this.otp).subscribe( 18 | response => { 19 | console.log(response); 20 | this.resetToken = response.resetToken; 21 | // Handle successful response 22 | }, 23 | error => { 24 | console.error(error); 25 | // Handle error 26 | } 27 | ); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/app/Components/layout/layout.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { UserHomeDataService } from 'src/app/Service/user-home-data.service'; 3 | @Component({ 4 | selector: 'app-layout', 5 | templateUrl: './layout.component.html', 6 | styleUrls: ['./layout.component.css'] 7 | }) 8 | export class LayoutComponent implements OnInit { 9 | 10 | extractedData: any 11 | notificationData: any 12 | cartData: any 13 | isCart: any 14 | id:any; 15 | 16 | constructor(private service: UserHomeDataService){ 17 | } 18 | ngOnInit(): void { 19 | 20 | this.service.getData().subscribe({ 21 | next:(data: any)=>{ 22 | this.notificationData = data["notifications"] 23 | if(data["carts"].length > 0) this.cartData = data["carts"][0].apartments 24 | else this.cartData = null 25 | 26 | } , 27 | error:(e:Error)=> console.log(e) 28 | }) 29 | 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /firebase.json: -------------------------------------------------------------------------------- 1 | { 2 | "database": { 3 | "rules": "database.rules.json" 4 | }, 5 | "emulators": { 6 | "database": { 7 | "port": 9000 8 | }, 9 | "hosting": { 10 | "port": 5000 11 | }, 12 | "ui": { 13 | "enabled": true 14 | }, 15 | "singleProjectMode": true 16 | }, 17 | "remoteconfig": { 18 | "template": "remoteconfig.template.json" 19 | }, 20 | "headers": [ 21 | { 22 | "source": "**/*.@(js|css|html)", 23 | "headers": [ 24 | { 25 | "key": "Cache-Control", 26 | "value": "max-age=604800" 27 | } 28 | ], 29 | "size": "3MB" 30 | } 31 | ], 32 | "hosting": { 33 | "public": "dist/agoura", 34 | "ignore": [ 35 | "firebase.json", 36 | "**/.*", 37 | "**/node_modules/**" 38 | ], 39 | "rewrites": [ 40 | { 41 | "source": "**", 42 | "destination": "/index.html" 43 | } 44 | ] 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Agoura 6 | 7 | 8 | 9 | 13 | 14 | 15 | 19 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /src/app/Components/footer-upper/footer-upper.component.html: -------------------------------------------------------------------------------- 1 | 27 | -------------------------------------------------------------------------------- /src/app/Components/forget-password/forget-password.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | import { Router } from '@angular/router'; 4 | import { ForgetPasswordService } from '../../Service/forget-password.service'; 5 | 6 | 7 | @Component({ 8 | selector: 'app-forget-password', 9 | templateUrl: './forget-password.component.html', 10 | styleUrls: ['./forget-password.component.css'] 11 | }) 12 | export class ForgetPasswordComponent { 13 | email: string =''; 14 | 15 | constructor(private forgetPasswordService: ForgetPasswordService, private router: Router) {} 16 | 17 | onSubmit() { 18 | this.forgetPasswordService.sendOTP(this.email).subscribe( 19 | response => { 20 | console.log(response); 21 | // Handle successful response and navigate to reset password page 22 | this.router.navigate(['/otp']); 23 | 24 | 25 | }, 26 | error => { 27 | console.error(error); 28 | // Handle error 29 | } 30 | ); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/app/Components/dashboard/views/dashboard-users/dashboard-users.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 |
NumberNameEmailOwned appartmentsNumber of bidsVerificationDelete
{{i+1}}{{user.name}}{{user.email}}{{user.ownedApartments.length}}{{user.bids.length}}{{user.isVerified}}
30 |
31 |
32 |
33 | -------------------------------------------------------------------------------- /src/app/Components/Profile/changepass/changepass.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
9 | 19 |
20 | Enter a vaild password more than 10 characters or numbers, this filed 22 | is required 24 |
25 | 26 |
27 |
28 |
29 | -------------------------------------------------------------------------------- /src/app/Components/dashboard/views/dashboard-users/dashboard-users.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { ActivatedRoute, Router } from '@angular/router'; 3 | import { DashboardTableService } from 'src/app/Service/dashboard-table.service'; 4 | 5 | @Component({ 6 | selector: 'app-dashboard-users', 7 | templateUrl: './dashboard-users.component.html', 8 | styleUrls: ['./dashboard-users.component.css'], 9 | }) 10 | export class DashboardUsersComponent implements OnInit { 11 | allUsers: any; 12 | constructor( 13 | private myService: DashboardTableService, 14 | private route: ActivatedRoute, 15 | private router: Router 16 | ) {} 17 | 18 | ngOnInit(): void { 19 | this.myService.GetAllUsers().subscribe({ 20 | next: (allData: any) => { 21 | console.log(allData.data) 22 | this.allUsers = allData.data; 23 | console.log(this.allUsers); 24 | }, 25 | error: (err: any) => { 26 | console.log(err); 27 | }, 28 | }); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */ 2 | { 3 | "compileOnSave": false, 4 | "compilerOptions": { 5 | "baseUrl": "./", 6 | "outDir": "./dist/out-tsc", 7 | "forceConsistentCasingInFileNames": true, 8 | "strict": true, 9 | "noImplicitOverride": true, 10 | "noPropertyAccessFromIndexSignature": true, 11 | "noImplicitReturns": true, 12 | "noFallthroughCasesInSwitch": true, 13 | "sourceMap": true, 14 | "declaration": false, 15 | "downlevelIteration": true, 16 | "experimentalDecorators": true, 17 | "moduleResolution": "node", 18 | "importHelpers": true, 19 | "target": "ES2022", 20 | "module": "ES2022", 21 | "useDefineForClassFields": false, 22 | "lib": [ 23 | "ES2022", 24 | "dom" 25 | ] 26 | }, 27 | "angularCompilerOptions": { 28 | "enableI18nLegacyMessageIdFormat": false, 29 | "strictInjectionParameters": true, 30 | "strictInputAccessModifiers": true, 31 | "strictTemplates": true 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/app/Components/Profile/apartments/apartments.component.html: -------------------------------------------------------------------------------- 1 |
2 | Create One 8 | 9 |
10 |

You Do Not Have Any Apartments Till Now

11 |
12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 |
TitleBidsStatus
{{ apartment.title | uppercase }}{{ apartment.bids.length }}{{ apartment.status | uppercase }}
31 |
32 |
33 | -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | // For more information, visit: https://go.microsoft.com/fwlink/?LinkId=733558 3 | "version": "2.0.0", 4 | "tasks": [ 5 | { 6 | "type": "npm", 7 | "script": "start", 8 | "isBackground": true, 9 | "problemMatcher": { 10 | "owner": "typescript", 11 | "pattern": "$tsc", 12 | "background": { 13 | "activeOnStart": true, 14 | "beginsPattern": { 15 | "regexp": "(.*?)" 16 | }, 17 | "endsPattern": { 18 | "regexp": "bundle generation complete" 19 | } 20 | } 21 | } 22 | }, 23 | { 24 | "type": "npm", 25 | "script": "test", 26 | "isBackground": true, 27 | "problemMatcher": { 28 | "owner": "typescript", 29 | "pattern": "$tsc", 30 | "background": { 31 | "activeOnStart": true, 32 | "beginsPattern": { 33 | "regexp": "(.*?)" 34 | }, 35 | "endsPattern": { 36 | "regexp": "bundle generation complete" 37 | } 38 | } 39 | } 40 | } 41 | ] 42 | } 43 | -------------------------------------------------------------------------------- /src/app/Components/dashboard/containers/default-layout/default-layout.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | 3 | import { navItems } from './_nav'; 4 | import { ProfilePageService } from 'src/app/Service/profile-page.service'; 5 | import { AuthService } from 'src/app/Service/auth.service'; 6 | 7 | @Component({ 8 | selector: 'app-dashboard', 9 | templateUrl: './default-layout.component.html', 10 | }) 11 | export class DefaultLayoutComponent implements OnInit{ 12 | user:any; 13 | constructor(private userService:ProfilePageService,private auth:AuthService){ 14 | 15 | } 16 | ngOnInit(): void { 17 | 18 | let user=this.auth.user(); 19 | if(user){ 20 | this.userService.GetUserByID(user.userId).subscribe({ 21 | next:(res:any)=>{ 22 | this.user=res|| "/assets/photos/avatar02.png"; 23 | }, 24 | error:(err:any)=>{ 25 | console.log(err) 26 | } 27 | }) 28 | } 29 | 30 | 31 | 32 | } 33 | 34 | public navItems = navItems; 35 | public perfectScrollbarConfig = { 36 | suppressScrollX: true, 37 | }; 38 | 39 | 40 | 41 | 42 | } 43 | -------------------------------------------------------------------------------- /src/app/Components/dashboard/views/bids/bids.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 |
NumberOwnerAddressTitleStatusTime LeftShow
{{i+1}}{{item.owner.name}}{{item.address.city}}{{item.title}}{{item.status}}{{item.timeLeft | date:'fullDate' }}
27 | 28 |

29 | -------------------------------------------------------------------------------- /src/app/Components/Profile/bids/bids.component.html: -------------------------------------------------------------------------------- 1 |
2 | Bid Now 8 | 9 |
10 |

You Do Not Have Any Bids Till Now

11 |
12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 31 | 32 | 33 | 34 | 35 | 36 |
ApartmentBidDate
27 | {{ 28 | bid.apartment.title 29 | }} 30 | {{ bid.amountMoney }}{{ bid.date | date : "dd/MM/yyyy" }}
37 |
38 |
39 | -------------------------------------------------------------------------------- /src/app/Components/Profile/orders/orders.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { ActivatedRoute, Router } from '@angular/router'; 3 | import { ProfilePageService } from 'src/app/Service/profile-page.service'; 4 | 5 | @Component({ 6 | selector: 'app-orders', 7 | templateUrl: './orders.component.html', 8 | styleUrls: ['./orders.component.css'] 9 | }) 10 | export class OrdersComponent implements OnInit { 11 | 12 | userId: any; 13 | orderData: any; 14 | result: any; 15 | constructor( 16 | private ProfileService: ProfilePageService, 17 | private router: ActivatedRoute, 18 | private route: Router 19 | ){ 20 | this.router.parent?.params.subscribe(data=>{ 21 | this.userId = data['id'] 22 | }) 23 | } 24 | 25 | ngOnInit(): void { 26 | 27 | this.ProfileService.getUserOrders(this.userId).subscribe({ 28 | next:(data: any)=>{ 29 | this.result = data 30 | if(!this.result.success){ 31 | this.route.navigateByUrl('/notfound') 32 | }else{ 33 | this.orderData = this.result.data 34 | console.log(this.orderData) 35 | } 36 | }, 37 | }) 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /src/app/Components/Payment/checkout/checkout.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { ActivatedRoute, Router } from '@angular/router'; 3 | import { CheckoutService } from 'src/app/Service/checkout.service'; 4 | 5 | @Component({ 6 | selector: 'app-checkout', 7 | templateUrl: './checkout.component.html', 8 | styles: [ 9 | ] 10 | }) 11 | export class CheckoutComponent implements OnInit { 12 | 13 | data:any; 14 | id:any; 15 | 16 | constructor(private http:CheckoutService,private checkoutService:CheckoutService,private route:ActivatedRoute,private router:Router){ 17 | this.id=this.route.snapshot.params['id']; 18 | } 19 | 20 | ngOnInit(): void { 21 | // for the aside info subtotal, taxes and total values 22 | console.log(this.id) 23 | this.http.getOrderDetails(this.id).subscribe({ 24 | next:(res:any)=>{ 25 | console.log(res.data) 26 | this.data=res.data 27 | console.log(res) 28 | } 29 | 30 | }) 31 | } 32 | submit(){ 33 | this.checkoutService.checkout(this.id,this.data).subscribe({ 34 | next:(res:any)=>{ 35 | console.log(res) 36 | window.location=res.url 37 | }, 38 | error:()=>{ 39 | } 40 | }) 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /src/app/Components/reset-password/reset-password.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | import { Router } from '@angular/router'; 3 | import { ResetPasswordService } from '../../Service/reset-password.service'; 4 | 5 | @Component({ 6 | selector: 'app-reset-password', 7 | templateUrl: './reset-password.component.html', 8 | styleUrls: ['./reset-password.component.css'] 9 | }) 10 | export class ResetPasswordComponent { 11 | newPassword: string = ''; 12 | confirmPassword: string = ''; 13 | resetToken: string = ''; 14 | 15 | constructor( 16 | private resetPasswordService: ResetPasswordService, 17 | private router: Router 18 | ) {} 19 | 20 | resetPassword() { 21 | this.resetPasswordService.resetPassword(this.resetToken, this.newPassword).subscribe( 22 | response => { 23 | console.log(response); 24 | // Handle successful response 25 | this.router.navigate(['/login']); 26 | }, 27 | error => { 28 | console.error(error); 29 | // Handle error 30 | } 31 | ); 32 | } 33 | 34 | onSubmit() { 35 | if (this.newPassword !== this.confirmPassword) { 36 | console.error('Passwords do not match'); 37 | return; 38 | } 39 | 40 | this.resetPassword(); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/app/Service/bids.service.ts: -------------------------------------------------------------------------------- 1 | import { HttpClient } from '@angular/common/http'; 2 | import { Injectable } from '@angular/core'; 3 | import {Environment} from "../../Environment/env" 4 | 5 | @Injectable({ 6 | providedIn: 'root', 7 | }) 8 | export class BidsService { 9 | private readonly Base_URL = Environment.apiUrl; 10 | constructor(private myClient: HttpClient) {} 11 | GetBidById(id: any) { 12 | return this.myClient.get(this.Base_URL + `/place/${id}`); 13 | } 14 | GetPendingBidById(id: any) { 15 | return this.myClient.get(this.Base_URL + `/place/${id}/edit`); 16 | } 17 | 18 | GetBidHistoryById(itemId: any) { 19 | return this.myClient.get(this.Base_URL + `/place/${itemId}/history`); 20 | } 21 | addNewBid(data: any) { 22 | return this.myClient.post(this.Base_URL + `/bid`,data); 23 | } 24 | updateBidById(id:number,data: any) { 25 | return this.myClient.put(this.Base_URL + `/bid/${id}/update`,data); 26 | } 27 | bidNeedsMoreInfo(id:number,data: any) { 28 | return this.myClient.post(this.Base_URL + `/bid/${id}/notes`,data); 29 | } 30 | approveBidById(id:number,data: any) { 31 | return this.myClient.post(this.Base_URL + `/bid/${id}/approve`,data); 32 | } 33 | 34 | cancelBidById(id:number,data: any) { 35 | return this.myClient.post(this.Base_URL + `/bid/${id}/cancel`,data); 36 | } 37 | 38 | 39 | 40 | } 41 | -------------------------------------------------------------------------------- /src/app/Components/offcanvas/offcanvas.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, Input } from '@angular/core'; 2 | import { UserHomeDataService } from 'src/app/Service/user-home-data.service'; 3 | 4 | @Component({ 5 | selector: 'app-offcanvas', 6 | templateUrl: './offcanvas.component.html', 7 | styleUrls: ['./offcanvas.component.css'] 8 | }) 9 | export class OffcanvasComponent { 10 | notificationData: any; 11 | cartData: any; 12 | cartError = false 13 | 14 | constructor(private home: UserHomeDataService){} 15 | 16 | @Input('isCart') toggle: any 17 | 18 | ngOnInit() { 19 | this.home.cartUpdated.subscribe((res) => { 20 | this.cartData = res.apartments; 21 | }); 22 | 23 | this.home.cartError.subscribe((res) => { 24 | this.cartError = res 25 | }); 26 | 27 | this.home.notificationUpdated.subscribe((res) => { 28 | this.notificationData = res; 29 | }); 30 | 31 | this.home.getData().subscribe({ 32 | next:(data: any)=>{ 33 | this.notificationData = data["notifications"] 34 | if(data["carts"].length > 0) this.cartData = data["carts"][0].apartments 35 | else this.cartData = null 36 | } , 37 | error:(e:Error)=> console.log(e) 38 | }) 39 | } 40 | 41 | deleteItem(id: any){ 42 | this.toggle ? this.home.deleteProductFromCart(id) : this.home.deleteNotification(id) 43 | } 44 | 45 | 46 | } 47 | -------------------------------------------------------------------------------- /src/assets/imgs/agora.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/app/Components/about/about.component.css: -------------------------------------------------------------------------------- 1 | section { 2 | padding: 4rem 0; 3 | } 4 | 5 | header { 6 | background-image: url('/assets/photos/Agoura.png'); 7 | background-repeat: no-repeat; 8 | background-position: center center; 9 | background-size: cover; 10 | height: 400px; 11 | } 12 | 13 | /*image { 14 | display: block; 15 | margin: 0 auto; 16 | max-width: 100%; 17 | max-height: 100%; 18 | width: 100%; 19 | height: 100%; 20 | }*/ 21 | 22 | img { 23 | 24 | 25 | border-radius: 10px; 26 | } 27 | 28 | 29 | .card { 30 | border: none; 31 | margin: 1rem; 32 | padding: 1.5rem; 33 | } 34 | 35 | .card:hover { 36 | transform: translateY(-5px); 37 | box-shadow: 0 0 10px rgba(0, 0, 0, 0.2); 38 | } 39 | 40 | /*.card-body { 41 | justify-content: center; 42 | align-items: center; 43 | height: 100%; 44 | }*/ 45 | 46 | .card-title { 47 | margin-bottom: 0.5rem; 48 | text-align: center; 49 | } 50 | 51 | .card-text { 52 | font-size: 1rem; 53 | font-weight: 400; 54 | color: #888; 55 | text-align: center; 56 | 57 | } 58 | 59 | .card-title, .card-text { 60 | font-family: 'Montserrat', sans-serif; 61 | font-style: italic; 62 | } 63 | 64 | .card-img-top { 65 | max-width: 250px; 66 | margin-bottom: 1rem; 67 | padding: 0; 68 | margin: 0 auto; 69 | display: block; 70 | border: 2px solid #fff; 71 | box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); 72 | } 73 | -------------------------------------------------------------------------------- /src/app/Components/Profile/changepass/changepass.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { FormControl, FormGroup, Validators } from '@angular/forms'; 3 | import { ActivatedRoute } from '@angular/router'; 4 | import { ProfilePageService } from 'src/app/Service/profile-page.service'; 5 | 6 | @Component({ 7 | selector: 'changepass-user', 8 | templateUrl: './changepass.component.html', 9 | styleUrls: ['./changepass.component.css'], 10 | }) 11 | export class ChangePassComponent implements OnInit { 12 | userId: any; 13 | validationForm: any; 14 | 15 | constructor( 16 | private route: ActivatedRoute, 17 | private myService: ProfilePageService 18 | ) { 19 | this.route.parent?.params.subscribe((data) => { 20 | this.userId = data['id']; 21 | }); 22 | } 23 | ngOnInit(): void { 24 | this.validationForm = new FormGroup({ 25 | password: new FormControl(null, [ 26 | Validators.required, 27 | Validators.minLength(3), 28 | ]), 29 | }); 30 | } 31 | 32 | get password() { 33 | return this.validationForm.controls['password'].valid; 34 | } 35 | 36 | isPasswordDirty() { 37 | return this.validationForm.controls['password'].dirty; 38 | } 39 | 40 | changePassword(id: any) { 41 | if (this.validationForm.valid) { 42 | const password = this.validationForm.controls['password'].value; 43 | this.myService.changeUserPassword(id, { password }).subscribe(); 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/app/Components/reset-password/reset-password.component.css: -------------------------------------------------------------------------------- 1 | .reset-password-container { 2 | margin: 50px auto; 3 | max-width: 450px; 4 | text-align: center; 5 | background-color: #f2f2f2; 6 | padding: 30px; 7 | border-radius: 10px; 8 | box-shadow: 0px 0px 10px rgba(0,0,0,0.3); 9 | } 10 | 11 | .reset-password-title { 12 | font-size: 36px; 13 | font-weight: bold; 14 | margin-bottom: 20px; 15 | color: #333; 16 | text-transform: uppercase; 17 | letter-spacing: 3px; 18 | } 19 | 20 | .reset-password-desc { 21 | font-size: 18px; 22 | margin-bottom: 30px; 23 | color: #555; 24 | } 25 | 26 | .reset-password-form { 27 | display: flex; 28 | flex-direction: column; 29 | align-items: center; 30 | } 31 | 32 | .reset-password-label { 33 | font-size: 18px; 34 | margin-bottom: 10px; 35 | color: #444; 36 | text-align: left; 37 | } 38 | 39 | .reset-password-input { 40 | padding: 10px; 41 | margin-bottom: 20px; 42 | border: none; 43 | border-radius: 5px; 44 | width: 100%; 45 | max-width: 350px; 46 | font-size: 18px; 47 | background-color: #f8f8f8; 48 | box-shadow: 0px 0px 5px rgba(0,0,0,0.1); 49 | } 50 | 51 | .reset-password-input:focus { 52 | outline: none; 53 | box-shadow: 0px 0px 5px rgba(0,0,0,0.3); 54 | } 55 | 56 | .reset-password-button { 57 | padding: 15px 30px; 58 | background-color: #4CAF50; 59 | color: white; 60 | border: none; 61 | border-radius: 5px; 62 | font-size: 20px; 63 | cursor: pointer; 64 | transition: background-color 0.2s ease-in-out; 65 | } 66 | 67 | .reset-password-button:hover { 68 | background-color: #3e8e41; 69 | } 70 | -------------------------------------------------------------------------------- /src/app/Components/bid-history/bid-history.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | import { ActivatedRoute } from '@angular/router'; 3 | import { NgxSpinnerService } from 'ngx-spinner'; 4 | import { BidsService } from 'src/app/Service/bids.service'; 5 | 6 | @Component({ 7 | selector: 'app-bid-history', 8 | templateUrl: './bid-history.component.html', 9 | styleUrls: ['./bid-history.component.css'], 10 | }) 11 | export class BidHistoryComponent { 12 | public constructor( 13 | private myService: BidsService, 14 | private route: ActivatedRoute, 15 | private spinner: NgxSpinnerService 16 | ) { 17 | this.id = route.snapshot.params['id']; 18 | } 19 | bids: any = {}; 20 | id: any; 21 | status: any 22 | 23 | placeBid() { 24 | console.log('place bid'); 25 | } 26 | 27 | ngOnInit(): void { 28 | let itemId = this.route.snapshot.params['id']; 29 | this.spinner.show('homeSpinner') 30 | this.myService.GetBidHistoryById(itemId).subscribe((data: any) => { 31 | data = data.data; 32 | console.log(data) 33 | this.bids.title = data.title; 34 | this.bids.image = data.image; 35 | this.bids.currentBid = data.currentBid; 36 | this.bids.itemNumber = data.itemNumber; 37 | this.bids.numberOfBids = data.numberOfBids; 38 | this.bids.numberOfBidders = data.numberOfBidders; 39 | this.bids.timeLeft = data.timeLeft; 40 | this.bids.duration = data.duration; 41 | this.bids.historyOfBids = data.historyOfBids; 42 | this.status = data.status 43 | this.spinner.hide('homeSpinner') 44 | }); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/assets/images/icons8-apple-logo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/app/Service/auth.service.ts: -------------------------------------------------------------------------------- 1 | import { HttpClient, HttpHeaderResponse, HttpHeaders } from '@angular/common/http'; 2 | import {Environment} from "../../Environment/env" 3 | import { Injectable } from '@angular/core'; 4 | import jwtDecode from 'jwt-decode'; 5 | @Injectable({ 6 | providedIn: 'root' 7 | }) 8 | export class AuthService { 9 | 10 | private readonly Base_URL = Environment.apiUrl; 11 | private headers=new HttpHeaders({'content-type': 'json/text'}); 12 | constructor(private myHttpClient:HttpClient) { 13 | 14 | } 15 | 16 | public signUp(user:any){ 17 | return this.myHttpClient.post(`${this.Base_URL}/register`,user) 18 | } 19 | public LoginWithGoogle(userCredential:any){ 20 | return this.myHttpClient.post(`${this.Base_URL}/auth/google`,userCredential,{'headers' : new HttpHeaders ({'Content-Type' : 'application/json'}), observe:'response'}) 21 | } 22 | 23 | public LoginWithSystem(userCredential:any){ 24 | return this.myHttpClient.post(`${this.Base_URL}/auth/login`,userCredential,{'headers' : new HttpHeaders ({'Content-Type' : 'application/json'}), observe:'response'}) 25 | } 26 | public verify(): boolean { 27 | const token = localStorage.getItem('X-Auth-Token'); 28 | 29 | if (token) { 30 | const decodedToken: any = jwtDecode(token); 31 | return decodedToken.isAdmin === true; 32 | } 33 | return false; 34 | } 35 | public user() { 36 | const token = localStorage.getItem('X-Auth-Token'); 37 | 38 | if (token) { 39 | const decodedToken: any = jwtDecode(token); 40 | return decodedToken 41 | } 42 | return false; 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /src/app/intercreptors/response.interceptor.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { 3 | HttpRequest, 4 | HttpHandler, 5 | HttpEvent, 6 | HttpInterceptor, 7 | HttpResponse, 8 | HttpErrorResponse, 9 | } from '@angular/common/http'; 10 | import { Observable } from 'rxjs'; 11 | import { tap } from 'rxjs/operators'; 12 | import { Router } from '@angular/router'; 13 | import { ToastService } from '../Service/toast-service.service'; 14 | 15 | @Injectable() 16 | export class ResponseInterceptor implements HttpInterceptor { 17 | constructor(private route: Router, private toastService: ToastService) {} 18 | 19 | intercept( 20 | req: HttpRequest, 21 | next: HttpHandler 22 | ): Observable> { 23 | return next.handle(req).pipe( 24 | tap({ 25 | next: (event) => { 26 | if (event.type === 4) { 27 | // Check if event is an HttpResponse 28 | if (event.status > 200 && event instanceof HttpResponse) { 29 | this.toastService.activateToast( 30 | event.body.message, 31 | event.body.success 32 | ); 33 | } 34 | } 35 | }, 36 | error: (event: HttpErrorResponse) => { 37 | if (event.status == 404) { 38 | this.route.navigateByUrl('404-notfound'); 39 | } 40 | if (event instanceof HttpErrorResponse) { 41 | this.toastService.activateToast( 42 | event.error.message, 43 | event.error.success 44 | ); 45 | } 46 | }, 47 | }) 48 | ); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/app/Components/Profile/changepass/changepass.component.css: -------------------------------------------------------------------------------- 1 | .feed-form { 2 | margin-top: 36px; 3 | display: flex; 4 | flex-direction: column; 5 | width: 100%; 6 | } 7 | 8 | .feed-form input { 9 | height: 54px; 10 | border-radius: 5px; 11 | background: white; 12 | margin: 15px 0; 13 | border: none; 14 | padding: 0 20px; 15 | font-weight: 300; 16 | font-size: 14px; 17 | color: #4B4B4B; 18 | } 19 | 20 | .feed-form input:hover { 21 | transform: scale(1.009); 22 | box-shadow: 0px 0px 3px 0px #212529; 23 | } 24 | 25 | 26 | .cart-btn { 27 | position: relative; 28 | font-size: 17px; 29 | text-transform: uppercase; 30 | text-decoration: none; 31 | padding: 1em 2.5em; 32 | display: inline-block; 33 | border-radius: 6em; 34 | transition: all .2s; 35 | border: none; 36 | font-family: inherit; 37 | font-weight: 500; 38 | color: white; 39 | background-color: black; 40 | width: 100%; 41 | margin: 5% 0; 42 | } 43 | 44 | .cart-btn:hover { 45 | transform: translateY(-3px); 46 | box-shadow: 0 10px 20px rgba(255, 255, 255, 0.8); 47 | } 48 | 49 | .cart-btn:active { 50 | transform: translateY(-1px); 51 | box-shadow: 0 5px 10px rgba(255, 255, 255, 0.8); 52 | } 53 | 54 | .cart-btn::after { 55 | content: ""; 56 | display: inline-block; 57 | height: 100%; 58 | width: 100%; 59 | border-radius: 100px; 60 | position: absolute; 61 | top: 0; 62 | left: 0; 63 | z-index: -1; 64 | transition: all .4s; 65 | } 66 | 67 | .cart-btn::after { 68 | background-color: black; 69 | } 70 | 71 | .cart-btn:hover::after { 72 | transform: scaleX(1.2) scaleY(1.6); 73 | opacity: 0; 74 | } 75 | 76 | -------------------------------------------------------------------------------- /src/app/Components/Profile/EditProfile/edit-profile/edit-profile.component.css: -------------------------------------------------------------------------------- 1 | .feed-form { 2 | margin-top: 36px; 3 | display: flex; 4 | flex-direction: column; 5 | width: 100%; 6 | } 7 | 8 | .feed-form input { 9 | height: 54px; 10 | border-radius: 5px; 11 | background: white; 12 | margin: 15px 0; 13 | border: none; 14 | padding: 0 20px; 15 | font-weight: 300; 16 | font-size: 14px; 17 | color: #4B4B4B; 18 | } 19 | 20 | .feed-form input:hover { 21 | transform: scale(1.009); 22 | box-shadow: 0px 0px 3px 0px #212529; 23 | } 24 | 25 | 26 | .cart-btn { 27 | position: relative; 28 | font-size: 17px; 29 | text-transform: uppercase; 30 | text-decoration: none; 31 | padding: 1em 2.5em; 32 | display: inline-block; 33 | border-radius: 6em; 34 | transition: all .2s; 35 | border: none; 36 | font-family: inherit; 37 | font-weight: 500; 38 | color: white; 39 | background-color: black; 40 | width: 100%; 41 | margin: 5% 0; 42 | } 43 | 44 | .cart-btn:hover { 45 | transform: translateY(-3px); 46 | box-shadow: 0 10px 20px rgba(255, 255, 255, 0.8); 47 | } 48 | 49 | .cart-btn:active { 50 | transform: translateY(-1px); 51 | box-shadow: 0 5px 10px rgba(255, 255, 255, 0.8); 52 | } 53 | 54 | .cart-btn::after { 55 | content: ""; 56 | display: inline-block; 57 | height: 100%; 58 | width: 100%; 59 | border-radius: 100px; 60 | position: absolute; 61 | top: 0; 62 | left: 0; 63 | z-index: -1; 64 | transition: all .4s; 65 | } 66 | 67 | .cart-btn::after { 68 | background-color: black; 69 | } 70 | 71 | .cart-btn:hover::after { 72 | transform: scaleX(1.2) scaleY(1.6); 73 | opacity: 0; 74 | } 75 | 76 | -------------------------------------------------------------------------------- /src/app/Service/profile-page.service.ts: -------------------------------------------------------------------------------- 1 | import { HttpClient } from '@angular/common/http'; 2 | import { EventEmitter, Injectable, Output } from '@angular/core'; 3 | import { NgxSpinnerService } from 'ngx-spinner'; 4 | import {Environment} from "../../Environment/env" 5 | 6 | @Injectable({ 7 | providedIn: 'root', 8 | }) 9 | export class ProfilePageService { 10 | 11 | private readonly Base_URL = Environment.apiUrl+'/users'; 12 | 13 | @Output() Image = new EventEmitter(); 14 | 15 | constructor( 16 | private readonly myClient: HttpClient, 17 | private spinner: NgxSpinnerService 18 | ) {} 19 | 20 | GetUserByID(id: any) { 21 | return this.myClient.get(this.Base_URL + '/' + id); 22 | } 23 | 24 | UpdateUser(newUser: any, id: any) { 25 | return this.myClient 26 | .put(this.Base_URL + '/' + id, newUser) 27 | .subscribe((info) => { 28 | this.Image.emit(info); 29 | this.spinner.hide('updateSpinner'); 30 | }); 31 | } 32 | 33 | getUserBids(id: any) { 34 | return this.myClient.get(this.Base_URL + '/' + id + '/bids'); 35 | } 36 | 37 | getUserOrders(id: any) { 38 | return this.myClient.get(this.Base_URL + '/' + id + '/orders'); 39 | } 40 | 41 | getUserApartments(id: any) { 42 | return this.myClient.get(this.Base_URL + '/' + id + '/apartments'); 43 | } 44 | 45 | changeUserPassword(id: any, newPass: any) { 46 | return this.myClient.put( 47 | this.Base_URL + '/' + id + '/changepassword', 48 | newPass 49 | ); 50 | } 51 | changeUserPicture(id: any, newImage: any) { 52 | return this.myClient.put(this.Base_URL + '/' + id + '/picture', newImage); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/app/Components/Profile/bids/bids.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core' 2 | import { ActivatedRoute, Router } from '@angular/router'; 3 | import { ProfilePageService } from 'src/app/Service/profile-page.service'; 4 | import jwt_decode from 'jwt-decode'; 5 | 6 | @Component({ 7 | selector: 'app-bids', 8 | templateUrl: './bids.component.html', 9 | styleUrls: ['./bids.component.css'] 10 | }) 11 | export class UserBidsComponent implements OnInit { 12 | 13 | userId: any; 14 | bidData: any; 15 | result: any; 16 | userToken: any; 17 | 18 | constructor( 19 | private ProfileService: ProfilePageService, 20 | private router: ActivatedRoute, 21 | private route: Router 22 | ){ 23 | this.router.parent?.params.subscribe(data=>{ 24 | this.userId = data['id'] 25 | }) 26 | this.userToken = localStorage.getItem('X-Auth-Token') 27 | } 28 | 29 | ngOnInit(): void { 30 | 31 | this.ProfileService.getUserBids(this.userId).subscribe({ 32 | next:(data: any)=>{ 33 | this.result = data 34 | console.log(data) 35 | if(!this.result.success){ 36 | this.route.navigateByUrl('/notfound') 37 | }else{ 38 | this.bidData = this.result.data 39 | } 40 | }, 41 | }) 42 | } 43 | 44 | decode(token: any){ 45 | if(token){ 46 | var decoded = jwt_decode(token) 47 | return decoded 48 | } 49 | return false 50 | } 51 | 52 | isAuthorized(){ 53 | const user : any = this.decode(this.userToken) 54 | if(user) return this.userId == user.userId 55 | return false 56 | } 57 | 58 | } 59 | 60 | 61 | -------------------------------------------------------------------------------- /src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | import { Title } from '@angular/platform-browser'; 3 | import { Router, NavigationEnd } from '@angular/router'; 4 | import { IconSetService } from '@coreui/icons-angular'; 5 | import { iconSubset } from './icons/icon-subset'; 6 | import { ToastService } from './Service/toast-service.service'; 7 | 8 | 9 | @Component({ 10 | selector: 'app-root', 11 | templateUrl: './app.component.html', 12 | styleUrls: ['./app.component.css'] 13 | }) 14 | export class AppComponent { 15 | title = 'Agoura'; 16 | toastMessage!: string; 17 | toastVisible=false; 18 | toastSuccess!:boolean; 19 | constructor( 20 | private router: Router, 21 | private titleService: Title, 22 | private iconSetService: IconSetService, 23 | private toastService: ToastService 24 | ) { 25 | titleService.setTitle(this.title); 26 | // iconSet singleton 27 | iconSetService.icons = { ...iconSubset }; 28 | } 29 | 30 | ngOnInit(): void { 31 | this.router.events.subscribe((evt) => { 32 | if (!(evt instanceof NavigationEnd)) { 33 | return; 34 | } 35 | }); 36 | this.toastService.toastEvent.subscribe((data:any) => { 37 | data=JSON.parse(data) 38 | this.toastMessage = data.message; 39 | this.toastSuccess=data.success; 40 | console.log(this.toastMessage) 41 | this.show() 42 | }); 43 | 44 | } 45 | show(){ 46 | if(this.toastMessage.length==0){ 47 | return 48 | } 49 | this.toastVisible=true 50 | setTimeout(()=>{ 51 | this.toastVisible=false 52 | this.toastMessage="" 53 | },4000) 54 | } 55 | 56 | 57 | } 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /src/app/Components/Profile/EditProfile/edit-profile/edit-profile.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
11 | 22 |
23 | Invalid User Name Must be minmum 3 charachters 24 |
25 | 37 | 40 | Change password? 42 | 43 | 44 |
45 |
46 |
47 | 48 |

Updating...

57 | -------------------------------------------------------------------------------- /src/app/Components/Auth/login/login.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | import { FormControl, FormGroup , Validators } from '@angular/forms'; 3 | import { Router } from '@angular/router'; 4 | import { AuthService } from 'src/app/Service/auth.service'; 5 | @Component({ 6 | selector: 'app-login', 7 | templateUrl: './login.component.html', 8 | styles: [ 9 | ] 10 | }) 11 | export class LoginComponent { 12 | public userData : any = {} ; 13 | public error!:string|null; 14 | public validationForm = new FormGroup({ 15 | email: new FormControl(null,[Validators.required, Validators.email]), 16 | password: new FormControl(null,[ Validators.required, Validators.minLength(8), Validators.maxLength(60) ]) 17 | }); 18 | constructor (private myService: AuthService , private route:Router) { } 19 | 20 | validate(){ 21 | if (this.validationForm.valid){ 22 | 23 | this.userData['email'] = this.validationForm.controls["email"].value; 24 | this.userData['password'] = this.validationForm.controls["password"].value; 25 | this.login(); 26 | } 27 | } 28 | get email () { 29 | return this.validationForm.controls["email"]; 30 | } 31 | get password () { 32 | return this.validationForm.controls["password"]; 33 | } 34 | 35 | login() { 36 | this.myService.LoginWithSystem(this.userData).subscribe({ 37 | next:(data:any)=>{ 38 | 39 | if(data.body.success){ 40 | localStorage.setItem('X-Auth-Token', data.body.myToken); 41 | this.route.navigateByUrl("/home"); 42 | } 43 | this.error = data.body.message; 44 | }, 45 | error:(err)=> { 46 | this.error = err.error.message; 47 | } 48 | } 49 | ) 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/app/Components/Profile/apartments/apartments.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | import { ActivatedRoute, Router } from '@angular/router'; 3 | import { ProfilePageService } from 'src/app/Service/profile-page.service'; 4 | import jwt_decode from "jwt-decode"; 5 | import { NgxSpinnerService } from 'ngx-spinner'; 6 | 7 | @Component({ 8 | selector: 'app-apartments', 9 | templateUrl: './apartments.component.html', 10 | styleUrls: ['./apartments.component.css'] 11 | }) 12 | export class ApartmentsComponent { 13 | 14 | userId: any; 15 | apartmentData: any; 16 | result: any; 17 | userToken: any 18 | 19 | constructor( 20 | private ProfileService: ProfilePageService, 21 | private router: ActivatedRoute, 22 | private route: Router, 23 | private spinner: NgxSpinnerService 24 | ){ 25 | this.router.parent?.params.subscribe((data: any)=>{ 26 | this.userId = data['id'] 27 | console.log(this.userId) 28 | }) 29 | this.userToken = localStorage.getItem('X-Auth-Token') 30 | } 31 | 32 | ngOnInit(): void { 33 | 34 | this.ProfileService.getUserApartments(this.userId).subscribe({ 35 | next:(data: any)=>{ 36 | this.result = data 37 | 38 | if(!this.result.success){ 39 | this.route.navigateByUrl('/notfound') 40 | }else{ 41 | this.apartmentData = this.result.data 42 | 43 | } 44 | }, 45 | }) 46 | 47 | } 48 | 49 | 50 | decode(token: any){ 51 | if(token){ 52 | var decoded = jwt_decode(token) 53 | return decoded 54 | } 55 | return false 56 | } 57 | 58 | isAuthorized(){ 59 | const user : any = this.decode(this.userToken) 60 | if(user) return this.userId == user.userId 61 | return false 62 | } 63 | 64 | 65 | } 66 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "agoura", 3 | "version": "0.0.0", 4 | "scripts": { 5 | "ng": "ng", 6 | "start": "ng serve", 7 | "build": "ng build", 8 | "watch": "ng build --watch --configuration development", 9 | "test": "ng test" 10 | }, 11 | "private": true, 12 | "dependencies": { 13 | 14 | "@angular/cdk": "^15.2.8", 15 | "@angular/common": "^15.2.0", 16 | "@angular/compiler": "^15.2.0", 17 | "@angular/core": "^15.2.0", 18 | "@angular/forms": "^15.2.0", 19 | "@angular/platform-browser": "^15.2.0", 20 | "@angular/platform-browser-dynamic": "^15.2.0", 21 | "@angular/router": "^15.2.0", 22 | "@coreui/angular": "^4.4.9", 23 | "@coreui/angular-chartjs": "^4.4.7", 24 | "@coreui/chartjs": "^3.1.1", 25 | "@coreui/icons": "^3.0.1", 26 | "@coreui/icons-angular": "^4.4.7", 27 | "@fortawesome/fontawesome-free": "^6.4.0", 28 | "@popperjs/core": "^2.11.6", 29 | "@types/google-one-tap": "^1.2.2", 30 | "animate.css": "^4.1.1", 31 | "bootstrap": "^5.2.3", 32 | "chart.js": "^3.9.1", 33 | "https": "^1.0.0", 34 | "json-server": "^0.17.3", 35 | "jwt-decode": "^3.1.2", 36 | "ngx-bootstrap": "^10.2.0", 37 | "ngx-perfect-scrollbar": "^10.1.1", 38 | "ngx-spinner": "^15.0.1", 39 | "nodemailer": "^6.9.1", 40 | "tslib": "^2.5.0", 41 | "zone.js": "~0.12.0" 42 | }, 43 | "devDependencies": { 44 | "@angular-devkit/build-angular": "^15.2.5", 45 | "@angular/cli": "~15.2.5", 46 | "@angular/compiler-cli": "^15.2.0", 47 | "@angular/localize": "^15.2.0", 48 | "@types/jasmine": "~4.3.0", 49 | "jasmine-core": "~4.5.0", 50 | "karma": "~6.4.0", 51 | "karma-chrome-launcher": "~3.1.0", 52 | "karma-coverage": "~2.2.0", 53 | "karma-jasmine": "~5.1.0", 54 | "karma-jasmine-html-reporter": "~2.0.0", 55 | "typescript": "~4.9.4" 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/app/Components/forget-password/forget-password.component.css: -------------------------------------------------------------------------------- 1 | .forget-password-container { 2 | display: flex; 3 | flex-direction: column; 4 | align-items: center; 5 | margin-top: 50px; 6 | } 7 | 8 | .forget-password-title { 9 | font-size: 36px; 10 | font-weight: bold; 11 | margin-bottom: 50px; 12 | text-align: center; 13 | color: #4CAF50; 14 | text-shadow: 2px 2px #fff; 15 | } 16 | 17 | .forget-password-form { 18 | display: flex; 19 | flex-direction: column; 20 | align-items: center; 21 | background-color: #fff; 22 | border-radius: 10px; 23 | box-shadow: 0 0 10px rgba(0, 0, 0, 0.2); 24 | padding: 40px; 25 | width: 400px; 26 | } 27 | 28 | .forget-password-label { 29 | font-size: 20px; 30 | margin-bottom: 20px; 31 | color: #4CAF50; 32 | } 33 | 34 | .forget-password-input { 35 | width: 300px; 36 | height: 50px; 37 | font-size: 20px; 38 | text-align: center; 39 | margin-bottom: 30px; 40 | border: none; 41 | background-color: #f2f2f2; 42 | border-radius: 10px; 43 | outline: none; 44 | box-shadow: 0 0 10px rgba(0, 0, 0, 0.2); 45 | } 46 | 47 | .forget-password-input:focus { 48 | background-color: #e6e6e6; 49 | } 50 | 51 | .forget-password-button { 52 | font-size: 24px; 53 | font-weight: bold; 54 | border: none; 55 | border-radius: 10px; 56 | padding: 10px 20px; 57 | cursor: pointer; 58 | background-color: #4CAF50; 59 | color: white; 60 | transition: background-color 0.2s ease-in-out; 61 | text-shadow: 1px 1px #fff; 62 | box-shadow: 0 0 10px rgba(0, 0, 0, 0.2); 63 | } 64 | 65 | .forget-password-button:hover { 66 | background-color: #3e8e41; 67 | } 68 | 69 | .forget-password-desc { 70 | font-size: 16px; 71 | margin-bottom: 50px; 72 | text-align: center; 73 | color: #666; 74 | font-family:Georgia, 'Times New Roman', Times, serif; 75 | font-style: normal; 76 | font-weight: 400; 77 | } 78 | -------------------------------------------------------------------------------- /src/app/Service/user-home-data.service.ts: -------------------------------------------------------------------------------- 1 | import { HttpClient } from '@angular/common/http'; 2 | import { EventEmitter, Injectable, Output } from '@angular/core'; 3 | import { NgxSpinnerService } from 'ngx-spinner'; 4 | import {Environment} from "../../Environment/env" 5 | 6 | @Injectable({ 7 | providedIn: 'root' 8 | }) 9 | export class UserHomeDataService { 10 | 11 | private BaseURL: string 12 | private BaseURLForFilter: string 13 | 14 | 15 | constructor(private user: HttpClient , private spinner: NgxSpinnerService) { 16 | this.BaseURL = Environment.apiUrl+"/home" 17 | this.BaseURLForFilter =Environment.apiUrl+'/home/apartments' 18 | } 19 | getData(){ 20 | return this.user.get(this.BaseURL) 21 | } 22 | @Output() cartUpdated = new EventEmitter(); 23 | @Output() notificationUpdated = new EventEmitter(); 24 | @Output() cartError = new EventEmitter(); 25 | 26 | 27 | deleteNotification(id: any){ 28 | this.user.delete(this.BaseURL+'/notifications/'+`${id}`).subscribe( 29 | (response) => { 30 | this.notificationUpdated.emit(response); 31 | }, 32 | (error) => { 33 | console.error('An error occurred while deleting the resource:', error); 34 | } 35 | ); 36 | } 37 | 38 | deleteProductFromCart(id: any){ 39 | this.user.delete(this.BaseURL+'/cart/'+`${id}`).subscribe( 40 | (response) => { 41 | this.cartUpdated.emit(response); 42 | }, 43 | (error) => { 44 | console.error('An error occurred while deleting the resource:', error.status); 45 | this.cartError.emit(true) 46 | } 47 | ); 48 | } 49 | 50 | addItemToCart(id: any){ 51 | this.user.post(this.BaseURL+'/cart', {id}).subscribe(response => { 52 | this.cartUpdated.emit(response); 53 | }, error => { 54 | console.error(error); 55 | }); 56 | } 57 | 58 | 59 | 60 | getFilteredData(category:any){ 61 | return this.user.get(this.BaseURLForFilter + "/" + category) 62 | 63 | } 64 | 65 | } 66 | -------------------------------------------------------------------------------- /src/app/Components/Auth/thirdPartyLoginButtons/google-button/google-button.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { Router } from '@angular/router'; 3 | import { CredentialResponse } from 'google-one-tap'; 4 | import { AuthService } from 'src/app/Service/auth.service'; 5 | 6 | @Component({ 7 | selector: 'app-google-button', 8 | templateUrl: './google-button.component.html', 9 | styleUrls: ['./google-button.component.css'] 10 | }) 11 | export class GoogleButtonComponent implements OnInit{ 12 | 13 | clientId="368777379420-2u8ltpji9p81k9cfako1nnnvaufjcu1j.apps.googleusercontent.com" 14 | constructor(private authService: AuthService, private router:Router) { } 15 | 16 | 17 | ngOnInit(): void { 18 | 19 | this.initialzeButton() 20 | } 21 | 22 | initialzeButton(){ 23 | // @ts-ignore 24 | google.accounts.id.initialize({ 25 | client_id: this.clientId, 26 | callback: this.handleCredentialResponse.bind(this), 27 | auto_select: false, 28 | cancel_on_tap_outside: true 29 | }); 30 | // @ts-ignore 31 | google.accounts.id.renderButton( 32 | // @ts-ignore 33 | document.getElementById("g_id_onload"), 34 | { theme: "outline", size: "large", width: "600", locale:"en",text:"continue_with",logo_alignment:"center"} 35 | ); 36 | // @ts-ignore 37 | google.accounts.id.prompt((notification: PromptMomentNotification) => {}); 38 | } 39 | 40 | async handleCredentialResponse(credential: CredentialResponse) { 41 | await this.authService.LoginWithGoogle(credential).subscribe( 42 | { 43 | next:(res:any)=>{ 44 | if(res.body.success){ 45 | localStorage.setItem("X-Auth-Token",res.headers.get("X-Auth-Token")); 46 | this.router.navigateByUrl("/home"); 47 | } 48 | console.log(res.headers.get("X-Auth-Token")) 49 | 50 | }, 51 | error:(err)=>{ 52 | console.log(err) 53 | } 54 | }); 55 | 56 | 57 | } 58 | 59 | 60 | 61 | 62 | 63 | } 64 | -------------------------------------------------------------------------------- /src/app/Components/dashboard/containers/default-layout/default-layout.component.html: -------------------------------------------------------------------------------- 1 | 2 | 8 | 24 | 25 | 44 | 45 | 46 | 47 | 48 | 52 | 53 | 54 | 59 | 60 | 61 | 62 |
63 | 64 | 65 | 66 |
67 | 68 | 69 | 70 |
71 | 72 | 73 |
74 | -------------------------------------------------------------------------------- /src/app/Components/otp/otp.component.css: -------------------------------------------------------------------------------- 1 | .otp-container { 2 | display: flex; 3 | flex-direction: column; 4 | align-items: center; 5 | margin-top: 50px; 6 | } 7 | 8 | .otp-logo { 9 | margin-bottom: 30px; 10 | } 11 | 12 | .otp-logo img { 13 | width: 150px; 14 | height: auto; 15 | } 16 | 17 | .otp-title { 18 | font-size: 36px; 19 | font-weight: bold; 20 | margin-bottom: 20px; 21 | text-align: center; 22 | color: #4CAF50; 23 | text-shadow: 2px 2px #fff; 24 | } 25 | 26 | .otp-form { 27 | display: flex; 28 | flex-direction: column; 29 | align-items: center; 30 | background-color: #fff; 31 | border-radius: 10px; 32 | box-shadow: 0 0 10px rgba(0, 0, 0, 0.2); 33 | padding: 40px; 34 | width: 400px; 35 | } 36 | 37 | .otp-inputs { 38 | display: flex; 39 | justify-content: center; 40 | margin-bottom: 30px; 41 | font-size: 28px; 42 | } 43 | 44 | .otp-inputs input[type="text"] { 45 | width: 150px; 46 | height: 80px; 47 | font-size: 36px; 48 | text-align: center; 49 | margin: 0 10px; 50 | border: none; 51 | background-color: #f2f2f2; 52 | border-radius: 10px; 53 | outline: none; 54 | box-shadow: 0 0 10px rgba(0, 0, 0, 0.2); 55 | } 56 | 57 | .otp-inputs input[type="text"]:focus { 58 | background-color: #e6e6e6; 59 | } 60 | 61 | .otp-actions { 62 | display: flex; 63 | justify-content: center; 64 | align-items: center; 65 | width: 100%; 66 | } 67 | 68 | .otp-resend-btn { 69 | font-size: 20px; 70 | color: #4CAF50; 71 | border: none; 72 | background-color: transparent; 73 | cursor: pointer; 74 | transition: color 0.2s ease-in-out; 75 | } 76 | 77 | .otp-resend-btn:hover { 78 | color: #3e8e41; 79 | } 80 | 81 | .otp-verify-btn { 82 | font-size: 24px; 83 | font-weight: bold; 84 | border: none; 85 | border-radius: 10px; 86 | padding: 10px 20px; 87 | cursor: pointer; 88 | background-color: #4CAF50; 89 | color: white; 90 | transition: background-color 0.2s ease-in-out; 91 | text-shadow: 1px 1px #fff; 92 | box-shadow: 0 0 10px rgba(0, 0, 0, 0.2); 93 | } 94 | 95 | .otp-verify-btn:hover { 96 | background-color: #3e8e41; 97 | } 98 | 99 | .forget-password-desc { 100 | font-size: 16px; 101 | margin-bottom: 50px; 102 | text-align: center; 103 | color: #666; 104 | font-family:Georgia, 'Times New Roman', Times, serif; 105 | font-style: normal; 106 | font-weight: 400; 107 | } 108 | -------------------------------------------------------------------------------- /src/app/Components/main-page-items-section/main-page-items-section.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | import { NgxSpinnerService } from 'ngx-spinner'; 3 | import { UserHomeDataService } from 'src/app/Service/user-home-data.service'; 4 | 5 | 6 | @Component({ 7 | 8 | selector: 'app-main-page-items-section', 9 | templateUrl: './main-page-items-section.component.html', 10 | styleUrls: ['./main-page-items-section.component.css'] 11 | 12 | }) 13 | export class MainPageItemsSectionComponent { 14 | 15 | 16 | items:any; 17 | addedCart = false 18 | 19 | constructor(public myService: UserHomeDataService, private spinner: NgxSpinnerService) { } 20 | 21 | ngOnInit(): void { 22 | this.spinner.show('homeSpinner') 23 | this.myService.getData().subscribe( 24 | { 25 | next: (data: any) => { 26 | this.items = data['apartments']; 27 | this.spinner.hide('homeSpinner') 28 | }, 29 | error: (err: any) => { console.log(err) } 30 | } 31 | ) 32 | } 33 | 34 | 35 | allcategories() { 36 | this.myService.getData().subscribe( 37 | { 38 | next: (data: any) => { 39 | this.items = data['apartments']; 40 | }, 41 | error: (err: any) => { console.log(err) } 42 | } 43 | ) 44 | } 45 | 46 | 47 | filterData(category: any) { 48 | 49 | this.myService.getFilteredData(category).subscribe({ 50 | next: (response: any) => { 51 | this.items = response.data 52 | }, 53 | error: (error: any) => { 54 | return error 55 | } 56 | }) 57 | } 58 | 59 | toggle(id: any , event: any){ 60 | const button = event.target 61 | 62 | if(!this.addedCart){ 63 | this.addToCart(id) 64 | button.innerText = 'Remove' 65 | button.classList.remove('cart-btn-add') 66 | button.classList.add('cart-btn-remove') 67 | button.removeEventListener('click', this.addToCart) 68 | button.addEventListener('click', this.removeFromCart) 69 | this.addedCart = true 70 | }else{ 71 | this.removeFromCart(id) 72 | button.innerHTML = 'Add To ' 73 | button.classList.remove('cart-btn-remove') 74 | button.classList.add('cart-btn-add') 75 | button.removeEventListener('click', this.removeFromCart) 76 | button.addEventListener('click', this.addToCart) 77 | this.addedCart = false 78 | } 79 | } 80 | addToCart(id: any){ 81 | this.myService.addItemToCart(id) 82 | } 83 | removeFromCart(id: any){ 84 | this.myService.deleteProductFromCart(id) 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/scss/_examples.scss: -------------------------------------------------------------------------------- 1 | .callout-info { 2 | background-color: $light-50 !important; 3 | 4 | @at-root .dark-theme & { 5 | background-color: rgba(255, 255, 255, .1) !important; 6 | } 7 | } 8 | 9 | .example { 10 | &:not(:first-child) { 11 | margin-top: 1.5rem; 12 | } 13 | 14 | .tab-content { 15 | background-color: $light-50 !important; 16 | 17 | @at-root .dark-theme & { 18 | background-color: rgba(255, 255, 255, .1) !important; 19 | } 20 | } 21 | 22 | code[class*="language-"], 23 | pre[class*="language-"] { 24 | font-size: .875rem !important; 25 | } 26 | 27 | :not(pre) > code[class*="language-"], 28 | pre[class*="language-"] { 29 | background: transparent; 30 | } 31 | 32 | & + p, 33 | & + h2, 34 | & + h3, 35 | & + h4, 36 | & + h5, 37 | & + h6 { 38 | margin-top: 1.5rem; 39 | } 40 | 41 | // Components examples 42 | .preview, 43 | .preview .col { 44 | + p { 45 | margin-top: 2rem; 46 | } 47 | 48 | > .form-control { 49 | + .form-control { 50 | margin-top: .5rem; 51 | } 52 | } 53 | 54 | > .nav + .nav, 55 | > .alert + .alert, 56 | > .navbar + .navbar, 57 | > .progress + .progress { 58 | margin-top: 1rem; 59 | } 60 | 61 | > .dropdown-menu { 62 | position: static; 63 | display: block; 64 | } 65 | 66 | > :last-child { 67 | margin-bottom: 0; 68 | } 69 | 70 | // Images 71 | > svg + svg, 72 | > img + img { 73 | margin-left: .5rem; 74 | } 75 | 76 | // Buttons 77 | > .btn, 78 | > .btn-group { 79 | margin: .25rem .125rem; 80 | } 81 | > .btn-toolbar + .btn-toolbar { 82 | margin-top: .5rem; 83 | } 84 | 85 | // List groups 86 | > .list-group { 87 | max-width: 400px; 88 | } 89 | 90 | > [class*="list-group-horizontal"] { 91 | max-width: 100%; 92 | } 93 | 94 | // Navbars 95 | .fixed-top, 96 | .sticky-top { 97 | position: static; 98 | margin: -1rem -1rem 1rem; 99 | } 100 | 101 | .fixed-bottom { 102 | position: static; 103 | margin: 1rem -1rem -1rem; 104 | } 105 | 106 | @include media-breakpoint-up(sm) { 107 | .fixed-top, 108 | .sticky-top { 109 | margin: -1.5rem -1.5rem 1rem; 110 | } 111 | .fixed-bottom { 112 | margin: 1rem -1.5rem -1.5rem; 113 | } 114 | } 115 | 116 | // Pagination 117 | .pagination { 118 | margin-top: .5rem; 119 | margin-bottom: .5rem; 120 | } 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /src/app/Components/nav-bar/nav-bar.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, EventEmitter, HostListener, Input, OnChanges, OnInit, Output, SimpleChanges } from '@angular/core'; 2 | import { UserHomeDataService } from 'src/app/Service/user-home-data.service'; 3 | import { BsDropdownConfig } from 'ngx-bootstrap/dropdown'; 4 | import { AuthService } from 'src/app/Service/auth.service'; 5 | 6 | @Component({ 7 | selector: 'app-nav-bar', 8 | templateUrl: './nav-bar.component.html', 9 | styleUrls: ['./nav-bar.component.css'], 10 | providers: [{ provide: BsDropdownConfig, useValue: { isAnimated: true, autoClose: true } }] 11 | 12 | }) 13 | export class NavBarComponent implements OnInit { 14 | cartLen: any; 15 | notLen: any; 16 | userId: any; 17 | profileImage:any; 18 | isAdmin=false; 19 | navElement: any 20 | constructor(public myService: UserHomeDataService ,private authService:AuthService) { 21 | 22 | } 23 | @HostListener("window:scroll", []) 24 | onWindowScroll() { 25 | if (window.scrollY > 0) { 26 | this.navElement.classList.add("nav-scrolled"); 27 | } else { 28 | this.navElement.classList.remove("nav-scrolled"); 29 | } 30 | } 31 | 32 | ngOnInit() { 33 | 34 | this.navElement = document.querySelector("#nav-con") 35 | this.myService.cartUpdated.subscribe((res) => { 36 | this.cartLen = res.apartments.length; 37 | }); 38 | this.myService.notificationUpdated.subscribe((res) => { 39 | this.notLen = res.length; 40 | }); 41 | this.myService.getData().subscribe({ 42 | next:(data: any)=>{ 43 | const {userData , notifications , carts} = data 44 | this.userId = userData ? userData._id : "notfound" 45 | this.userName = userData ? userData.name.split(" ")[0] : 'Guest' 46 | this.notLen = notifications ? notifications.length : 0 47 | this.cartLen = carts.length > 0 ? data['carts'][0]['apartments'].length : this.cartLen 48 | this.profileImage = userData ? userData.image : "/assets/photos/avatar02.png" 49 | this.isLoggedIn = localStorage.getItem('X-Auth-Token') 50 | } 51 | }) 52 | this.isAdmin=this.authService.verify(); 53 | 54 | } 55 | 56 | @Input("text-color") inputTextColor!:string; 57 | textColor!:string; 58 | element: any; 59 | @Output() toggle = new EventEmitter() 60 | userName: string = ' ' 61 | isLoggedIn: any 62 | 63 | check(data: any){ 64 | this.element = data.target.parentElement 65 | if(this.element.id === 'cart'){ 66 | this.toggle.emit(true) 67 | }else{ 68 | this.toggle.emit(false) 69 | } 70 | } 71 | 72 | logout(){ 73 | localStorage.removeItem('X-Auth-Token') 74 | } 75 | } 76 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /src/app/Components/main-page-items-section/main-page-items-section.component.css: -------------------------------------------------------------------------------- 1 | .custom-image{ 2 | width:100%; 3 | aspect-ratio: 1; 4 | object-fit: cover; 5 | border-radius: 15px; 6 | 7 | } 8 | 9 | .filter-btn { 10 | display: inline-block; 11 | width: 150px; 12 | height: 50px; 13 | position: relative; 14 | overflow: hidden; 15 | transition: all 0.5s ease-in; 16 | z-index: 1; 17 | border-style: none; 18 | } 19 | 20 | .filter-btn::before, 21 | .filter-btn::after { 22 | content: ''; 23 | position: absolute; 24 | top: 0; 25 | width: 0; 26 | height: 100%; 27 | transform: skew(15deg); 28 | transition: all 0.5s; 29 | overflow: hidden; 30 | z-index: -1; 31 | } 32 | 33 | .filter-btn::before { 34 | left: -10px; 35 | background: #099DFD; 36 | } 37 | 38 | .filter-btn::after { 39 | right: -10px; 40 | background: #099DFD; 41 | } 42 | 43 | .filter-btn:hover::before, 44 | .filter-btn:hover::after { 45 | width: 58%; 46 | } 47 | 48 | .filter-btn:hover span { 49 | color: #eeee; 50 | transition: 0.3s; 51 | } 52 | 53 | .filter-btn span { 54 | color: #eeee; 55 | font-size: 18px; 56 | transition: all 0.3s ease-in; 57 | } 58 | 59 | .cart-btn-add , .cart-btn-remove { 60 | position: relative; 61 | font-size: 17px; 62 | text-transform: uppercase; 63 | text-decoration: none; 64 | padding: .8em 2em; 65 | display: inline-block; 66 | border-radius: 6em; 67 | transition: all .2s; 68 | border: none; 69 | font-family: inherit; 70 | font-weight: 500; 71 | color: white; 72 | width: 100%; 73 | } 74 | 75 | .cart-btn-add{ 76 | background-color: black; 77 | } 78 | 79 | .cart-btn-remove{ 80 | background-color: rgb(122, 122, 122); 81 | } 82 | 83 | .cart-btn-add:hover , .cart-btn-remove:hover { 84 | transform: translateY(-3px); 85 | box-shadow: 0 10px 20px rgba(255, 255, 255, 0.8); 86 | } 87 | 88 | .cart-btn-add:active , .cart-btn-remove:active { 89 | transform: translateY(-1px); 90 | box-shadow: 0 5px 10px rgba(255, 255, 255, 0.8); 91 | } 92 | 93 | .cart-btn-add::after , .cart-btn-remove::after { 94 | content: ""; 95 | display: inline-block; 96 | height: 100%; 97 | width: 100%; 98 | border-radius: 100px; 99 | position: absolute; 100 | top: 0; 101 | left: 0; 102 | z-index: -1; 103 | transition: all .4s; 104 | } 105 | 106 | .cart-btn-add::after { 107 | background-color: black; 108 | } 109 | 110 | .cart-btn-remove::after { 111 | background-color: rgb(88, 88, 88); 112 | } 113 | 114 | .cart-btn-add:hover::after , .cart-btn-remove:hover::after{ 115 | transform: scaleX(1.2) scaleY(1.6); 116 | opacity: 0; 117 | } 118 | 119 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Agora - Frontend 2 | 3 | This is the frontend application for Agora, a property auction platform built with Angular. Agora allows users to browse property auctions, place bids, and participate in the auction process. 4 | 5 | ## Table of Contents 6 | 7 | - [Project Overview](#project-overview) 8 | - [Installation](#installation) 9 | - [Usage](#usage) 10 | - [Dependencies](#dependencies) 11 | - [Contributors](#contributors) 12 | 13 | ## Project Overview 14 | 15 | The Agora frontend is a single-page application built with Angular. It provides a user-friendly interface for interacting with the Agora auction platform. The frontend integrates with the Agora backend API to fetch data and perform actions such as bidding on properties and managing user accounts. 16 | - [server github link](https://github.com/AhmedMohamedZein/Agoura-Node) 17 | - [live website](https://agora-4.web.app) 18 | 19 | ## Installation 20 | 21 | To install and set up the Agora frontend locally, follow these steps: 22 | 23 | 1. Clone the repository: `git clone https://github.com/Mohamedyousef44/Agoura-Angular.git` 24 | 2. Navigate to the project directory: `cd agora-frontend` 25 | 3. Install the dependencies: `npm install` 26 | 4. Set up the required configuration: 27 | 5. Run the application: `npm start` 28 | 29 | ## Usage 30 | 31 | To use the Agora frontend, follow these steps: 32 | 33 | 1. Access the application through the provided URL or local development server. 34 | 2. Register an account or log in with existing credentials. 35 | 3. Browse available property auctions. 36 | 4. View auction details, including property information, starting price, and current bids. 37 | 5. Place bids on desired properties. 38 | 6. Monitor auction status and outbid other users. 39 | 7. If you win an auction, follow the instructions to complete the payment process. 40 | 41 | ## Dependencies 42 | 43 | The Agora frontend relies on the following dependencies: 44 | 45 | - [Angular](https://angular.io/) - A powerful framework for building web applications. 46 | - [Ngx Spinner](https://www.npmjs.com/package/ngx-spinner) - A library for displaying loading spinners in Angular. 47 | - [Ngx Angular](https://github.com/ngx-rocket/starter-kit) - A starter kit for Angular projects. 48 | - [CoreUI](https://coreui.io/) - A UI library for building responsive web applications. 49 | 50 | 51 | 52 | ## Contributors 53 | 54 | The contributors to the Agora frontend include: 55 | - [Ahmed Hamada](https://github.com/AhmedHamada011) 56 | - [Ahmed Zain](https://avatars.githubusercontent.com/u/74258945?s=64&v=4) 57 | - [Mahmoud Elbasiony](https://github.com/mahmoud-elbasiony) 58 | - [Mohamed Yossef](https://github.com/Mohamedyousef44) 59 | - [Omar Alaa](https://github.com/omar1896) 60 | - [Mostafa Ashraf](https://github.com/Mostafaa133) 61 | 62 | 63 | -------------------------------------------------------------------------------- /src/app/Components/Payment/payment-method/payment-method.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | import { FormControl, FormGroup, Validators } from '@angular/forms'; 3 | import { ActivatedRoute, Router } from '@angular/router'; 4 | import { CheckoutService } from 'src/app/Service/checkout.service'; 5 | 6 | @Component({ 7 | selector: 'app-payment-method', 8 | templateUrl: './payment-method.component.html', 9 | styles: [ 10 | ] 11 | }) 12 | export class PaymentMethodComponent { 13 | id:any; 14 | public customerPaymentInfo : any = {} ; 15 | public validationForm = new FormGroup({ 16 | name: new FormControl(null,[Validators.required, Validators.pattern('^[a-zA-Z ]*$'), Validators.maxLength(32) , Validators.minLength(15)]), 17 | cardNumber : new FormControl(null,[Validators.required , Validators.minLength(16)]), 18 | expiryDate: new FormControl(null, [Validators.required, Validators.pattern('^(0[1-9]|1[0-2])\/([0-9]{4}|[0-9]{2})$') , Validators.minLength(5) ] ), 19 | cvv : new FormControl(null , [Validators.required, Validators.minLength(3)]) 20 | }); 21 | constructor(private checkoutService:CheckoutService,private route:ActivatedRoute,private router:Router){ 22 | this.id=this.route.snapshot.params['id']; 23 | 24 | } 25 | 26 | validate(){ 27 | if (this.validationForm.valid){ 28 | this.customerPaymentInfo["name"] = this.validationForm.controls["name"].value; 29 | this.customerPaymentInfo["cardNumber"] = this.validationForm.controls["cardNumber"].value; 30 | this.customerPaymentInfo["expiryDate"] = this.validationForm.controls["expiryDate"].value; 31 | this.customerPaymentInfo["cvv"] = this.validationForm.controls["cvv"].value; 32 | 33 | // HTTP 1.1 Post to the server-side 34 | this.checkoutService.checkout(this.id,this.validationForm.value).subscribe({ 35 | next:(res:any)=>{ 36 | console.log(res) 37 | window.location=res.url 38 | }, 39 | error:()=>{ 40 | } 41 | }) 42 | 43 | } 44 | } 45 | get name () { 46 | return this.validationForm.controls["name"].valid; 47 | } 48 | get cardNumber () { 49 | return this.validationForm.controls["cardNumber"].valid; 50 | } 51 | get expiryDate () { 52 | return this.validationForm.controls["expiryDate"].valid; 53 | } 54 | get cvv () { 55 | return this.validationForm.controls["cvv"].valid 56 | } 57 | isNameDirty(){ 58 | return this.validationForm.controls["name"].dirty; 59 | } 60 | isCardNumberDirty(){ 61 | return this.validationForm.controls["cardNumber"].dirty; 62 | } 63 | isCVVDirty() { 64 | return this.validationForm.controls["cvv"].dirty; 65 | } 66 | 67 | isExpiryDateDirty(){ 68 | return this.validationForm.controls["expiryDate"].dirty; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/app/Components/main-page-items-section/main-page-items-section.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 |
5 |
6 | 12 | 18 | 24 | 30 | 31 | 37 | 43 |
44 |
45 | 46 |
47 |
48 |
52 | 53 | 54 | 55 | first slide 61 | 62 | 63 |
64 |
65 | {{ item.title | uppercase }} 66 |
67 |
68 | {{ item.address.city | uppercase }},{{ 69 | item.address.country | uppercase 70 | }} 71 |
72 |
73 | Starts From: {{ item.startBid | currency }} 74 |
75 | 82 |
83 |
84 |
85 |
86 |
87 |
88 | -------------------------------------------------------------------------------- /src/app/Components/product-details/product-details.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { FormControl,FormGroup, Validators } from '@angular/forms'; 3 | import { ActivatedRoute, Router } from '@angular/router'; 4 | import { NgxSpinnerService } from 'ngx-spinner'; 5 | import { BidsService } from 'src/app/Service/bids.service'; 6 | import { ToastService } from 'src/app/Service/toast-service.service'; 7 | 8 | @Component({ 9 | selector: 'app-product-details', 10 | templateUrl: './product-details.component.html', 11 | styleUrls: ['./product-details.component.css'] 12 | }) 13 | export class ProductDetailsComponent implements OnInit{ 14 | 15 | form!:FormGroup; 16 | placeObj!:any; 17 | maxBid!:number; 18 | thumbnail!:any; 19 | public constructor(private myService:BidsService,private route:ActivatedRoute,private router:Router,private toastService: ToastService , private spinner: NgxSpinnerService){ 20 | 21 | } 22 | ngOnInit(): void { 23 | let bidId=this.route.snapshot.params["id"] 24 | this.spinner.show('homeSpinner') 25 | this.myService.GetBidById(bidId).subscribe({ 26 | next:(res:any)=>{ 27 | if(res.success){ 28 | this.populate(res) 29 | } 30 | this.spinner.hide('homeSpinner') 31 | }, 32 | error:(err)=>{ 33 | this.router.navigateByUrl(`404-NotFound`) 34 | console.log(err) 35 | } 36 | }) 37 | 38 | } 39 | 40 | public populate(res:any){ 41 | this.placeObj=res.data.appartment 42 | if(this.placeObj.bids.length>0){ 43 | this.maxBid=res.data.appartment.bids[0].amountMoney 44 | }else{ 45 | this.maxBid=res.data.appartment.startBid 46 | } 47 | this.thumbnail=res.data.appartment.images[0] 48 | this.form=new FormGroup({ 49 | bid: new FormControl(this.maxBid,Validators.min(this.maxBid+1)), 50 | }) 51 | } 52 | 53 | public changeImage(event:any){ 54 | this.thumbnail=event.target.src 55 | } 56 | get bid(){ 57 | return this.form.get("bid"); 58 | } 59 | 60 | onSubmit(){ 61 | this.bid?.markAsDirty() 62 | if(!localStorage.getItem("X-Auth-Token")){ 63 | this.toastService.activateToast( 64 | "you need to login first.", 65 | false 66 | ); 67 | } 68 | if(!this.form.valid){ 69 | return 70 | } 71 | // toDo add form submit logic here 72 | let data={ 73 | amountMoney:this.bid!.value, 74 | apartmentID:this.placeObj._id, 75 | userToken:localStorage.getItem("X-Auth-Token") 76 | } 77 | 78 | this.myService.addNewBid(data).subscribe( 79 | { 80 | next:(res:any)=>{ 81 | if(res.success){ 82 | this.populate(res) 83 | 84 | } 85 | }, 86 | error:(err)=>{ 87 | console.log(err) 88 | } 89 | } 90 | ); 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/app/Components/dashboard/views/dashboard-bid-details/dashboard-bid-details.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { ActivatedRoute, Router } from '@angular/router'; 3 | import { BidsService } from 'src/app/Service/bids.service'; 4 | import { FormControl,FormGroup, Validators } from '@angular/forms'; 5 | import { DashboardTableService } from 'src/app/Service/dashboard-table.service'; 6 | 7 | @Component({ 8 | selector: 'app-dashboard-bid-details', 9 | templateUrl: './dashboard-bid-details.component.html', 10 | styleUrls: ['./dashboard-bid-details.component.css'] 11 | }) 12 | export class DashboardBidDetailsComponent implements OnInit{ 13 | 14 | placeObj:any; 15 | form!:FormGroup; 16 | constructor(private dasboardService:DashboardTableService,private myService:BidsService,private route:ActivatedRoute,private router:Router){ 17 | 18 | } 19 | sendNotes(){ 20 | if(this.form.valid){ 21 | this.myService.bidNeedsMoreInfo(this.placeObj._id,this.form.value).subscribe({ 22 | next:(res:any)=>{ 23 | console.log(res) 24 | if(res.success){ 25 | this.placeObj=res.data.appartment 26 | } 27 | // this.router.navigateByUrl("/dashboard/bids/"+this.route.snapshot.params["id"]) 28 | }, 29 | error:(err)=>{ 30 | console.log(err) 31 | } 32 | }) 33 | } 34 | } 35 | approve(){ 36 | this.myService.approveBidById(this.placeObj._id,{_id:this.placeObj._id}).subscribe({ 37 | next:(res:any)=>{ 38 | console.log(res) 39 | if(res.success){ 40 | this.placeObj=res.data.appartment 41 | } 42 | 43 | // this.router.navigateByUrl("/dashboard/bids/"+this.route.snapshot.params["id"]) 44 | }, 45 | error:(err)=>{ 46 | console.log(err) 47 | } 48 | }) 49 | } 50 | cancel(){ 51 | this.myService.cancelBidById(this.placeObj._id,{_id:this.placeObj._id}).subscribe({ 52 | next:(res:any)=>{ 53 | console.log(res) 54 | if(res.success){ 55 | this.placeObj=res.data.appartment 56 | } 57 | 58 | // this.router.navigateByUrl("/dashboard/bids/"+this.route.snapshot.params["id"]) 59 | }, 60 | error:(err)=>{ 61 | console.log(err) 62 | } 63 | }) 64 | } 65 | ngOnInit(): void { 66 | this.form=new FormGroup({ 67 | notes: new FormControl("",Validators.minLength(10)), 68 | }) 69 | let placeId=this.route.snapshot.params["id"] 70 | this.dasboardService.GetPlaceById(placeId).subscribe({ 71 | next:(res:any)=>{ 72 | console.log(res) 73 | if(res.success){ 74 | this.placeObj=res.data.appartment 75 | console.log(res.data.appartment.images) 76 | } 77 | }, 78 | error:(err)=>{ 79 | this.router.navigateByUrl(`404-NotFound`) 80 | console.log(err) 81 | } 82 | }) 83 | 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/app/Components/Auth/sign-up/sign-up.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | import { FormControl, FormGroup, Validators } from '@angular/forms'; 3 | import { Router } from '@angular/router'; 4 | import { AuthService } from 'src/app/Service/auth.service'; 5 | 6 | @Component({ 7 | selector: 'app-sign-up', 8 | templateUrl: './sign-up.component.html', 9 | styles: [ 10 | ] 11 | }) 12 | export class SignUpComponent { 13 | public userData : any = {} 14 | public error!:string|null; 15 | public validationForm:FormGroup ; 16 | 17 | public constructor(private myService:AuthService,private route:Router){ 18 | 19 | this.validationForm = new FormGroup({ 20 | email: new FormControl(null,[Validators.required, Validators.email]), 21 | username : new FormControl (null,[Validators.required , Validators.minLength(3)]), 22 | password: new FormControl(null,[ Validators.required, Validators.minLength(10), Validators.maxLength(60) ]), 23 | confirmPassword : new FormControl(null , [Validators.required , Validators.minLength(10), Validators.maxLength(60) ]) 24 | }); 25 | } 26 | 27 | validate(){ 28 | if (this.validationForm.valid){ 29 | this.userData['email'] = this.validationForm.controls["email"].value ; 30 | this.userData['name'] = this.validationForm.controls["username"].value ; 31 | this.userData['password'] = this.validationForm.controls["password"].value ; 32 | this.userData['confirmPassword'] = this.validationForm.controls["confirmPassword"].value ; 33 | this.error=null; 34 | this.signUp() 35 | } 36 | } 37 | get email () { 38 | return this.validationForm.controls["email"].valid; 39 | } 40 | 41 | get username () { 42 | return this.validationForm.controls["username"].valid; 43 | } 44 | 45 | get password () { 46 | return this.validationForm.controls["password"].valid; 47 | } 48 | 49 | get confirmPassword () { 50 | return this.validationForm.controls["confirmPassword"].valid; 51 | } 52 | 53 | isEmailDirty(){ 54 | return this.validationForm.controls["email"].dirty; 55 | } 56 | isUsernameDirty(){ 57 | return this.validationForm.controls["username"].dirty; 58 | } 59 | isPasswordDirty(){ 60 | return this.validationForm.controls["password"].dirty; 61 | } 62 | 63 | isConfirmPasswordDirty(){ 64 | return this.validationForm.controls["confirmPassword"].dirty; 65 | } 66 | 67 | arePasswordsEqual() { 68 | if ( this.validationForm.controls["password"].value == this.validationForm.controls["confirmPassword"].value) { 69 | return false; 70 | } 71 | else { 72 | return true; 73 | } 74 | } 75 | signUp(){ 76 | this.myService.signUp(this.userData).subscribe( 77 | { 78 | next:(data:any)=>{ 79 | if(data.success){ 80 | this.route.navigateByUrl("/login") 81 | } 82 | this.error=data.message; 83 | }, 84 | error:(err)=>err 85 | } 86 | ) 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/app/Components/Auth/login/login.component.html: -------------------------------------------------------------------------------- 1 |
2 | 10 |
14 |

19 | Log in to Agoura 20 |

21 |
24 | 25 |
26 |
33 |
34 | {{ error }} 37 | 38 |
39 |
40 | 43 | 50 |
51 |
52 | Enter a vaild email address, this filed is required 56 |
57 |
58 | 59 | 67 |
68 |
69 | This password is Invalid 73 |
74 | 75 |
76 |
77 | Forget Password ? 78 |
79 |
80 | Don't have an account? 81 | Sign up 82 |
83 |
84 |
85 |
86 | -------------------------------------------------------------------------------- /src/app/Components/offcanvas/offcanvas.component.html: -------------------------------------------------------------------------------- 1 |
9 |
10 |
11 | {{ toggle == true ? "Cart" : "Notifications" }} 12 |
13 | 19 |
20 |
21 | 87 |
88 |
89 | -------------------------------------------------------------------------------- /src/app/Components/Profile/profile/profile.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { FormControl, FormGroup } from '@angular/forms'; 3 | import { ActivatedRoute } from '@angular/router'; 4 | import { NgxSpinnerService } from 'ngx-spinner'; 5 | import { ProfilePageService } from 'src/app/Service/profile-page.service'; 6 | import jwt_decode from 'jwt-decode'; 7 | 8 | @Component({ 9 | selector: 'app-profile', 10 | templateUrl: './profile.component.html', 11 | styleUrls: ['./profile.component.css'], 12 | }) 13 | export class ProfileComponent implements OnInit { 14 | userID: any; 15 | UserDetails: any; 16 | userImage = " "; 17 | validationForm: any; 18 | profileValid = false; 19 | userToken: any; 20 | 21 | constructor( 22 | public myService: ProfilePageService, 23 | public route: ActivatedRoute, 24 | private spinner: NgxSpinnerService 25 | ) { 26 | this.route.params.subscribe((params) => { 27 | this.userID = params['id']; 28 | }); 29 | this.userToken = localStorage.getItem('X-Auth-Token') 30 | } 31 | 32 | goDown() { 33 | window.scroll(0, 630); 34 | } 35 | 36 | ngOnInit(): void { 37 | 38 | this.myService.Image.subscribe((info) => { 39 | this.userImage = info.data.image; 40 | }); 41 | 42 | this.spinner.show('homeSpinner'); 43 | this.myService.GetUserByID(this.userID).subscribe({ 44 | next: (data: any) => { 45 | this.UserDetails = data; 46 | const image = data.image; 47 | if (image) this.userImage = image 48 | else this.userImage = '/assets/imgs/default.jpg'; 49 | this.spinner.hide('homeSpinner'); 50 | 51 | this.validationForm = new FormGroup({ 52 | profileImage: new FormControl(null), 53 | }); 54 | }, 55 | error: (err: any) => { 56 | console.log(err); 57 | }, 58 | }); 59 | } 60 | 61 | onFileSelected(event: any) { 62 | if (this.validateFile(event.target.files[0].name)) { 63 | this.profileValid = true; 64 | this.userImage = event.target.files[0]; 65 | return; 66 | } 67 | } 68 | 69 | validateFile(name: string) { 70 | let ext = name.substring(name.lastIndexOf('.') + 1); 71 | if (ext.toLowerCase() == 'png' || ext.toLowerCase() == 'jpg') { 72 | return true; 73 | } else { 74 | return false; 75 | } 76 | } 77 | 78 | changeImage() { 79 | const fd = new FormData(); 80 | fd.append('profileImage', this.userImage); 81 | this.myService.changeUserPicture(this.userID, fd).subscribe({ 82 | next: (response: any) => { 83 | this.userImage = response.data['image']; 84 | }, 85 | }); 86 | } 87 | 88 | decode(token: any){ 89 | if(token){ 90 | var decoded = jwt_decode(token) 91 | return decoded 92 | } 93 | return false 94 | } 95 | 96 | isAuthorized(){ 97 | const user : any = this.decode(this.userToken) 98 | if(user) return this.userID == user.userId 99 | return false 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /src/app/Components/Payment/checkout/checkout.component.html: -------------------------------------------------------------------------------- 1 |
2 | 5 |
6 |
7 |
8 | 11 |

{{data.title | uppercase}}

12 | 13 |
14 |
15 | 59 |
60 |
61 |
62 |
63 | -------------------------------------------------------------------------------- /src/app/Components/Payment/payment-method/payment-method.component.html: -------------------------------------------------------------------------------- 1 |
2 |

Payment Method

3 |
4 |
5 | 6 |
7 | 8 | 9 |
10 |
11 |
12 | Enter a vaild name without numbers or special characters 13 |
14 |
15 | 16 |
17 | 18 | 19 |
20 |
21 |
22 | Enter a vaild credit card number it should be 16 digits 23 |
24 |
25 |
26 | 27 |
28 | 29 | 30 |
31 |
32 | Enter a vaild expiry date, The exact like in your credit card 12/24 33 |
34 |
35 | 36 |
37 | 38 | 39 |
40 | 41 | Enter a vaild CVV number, 42 | What's CVV? 43 | 44 |
45 |
46 | 47 |
48 | 49 |
50 |
-------------------------------------------------------------------------------- /src/app/Components/dashboard/views/charts/charts.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { DashboardTableService } from 'src/app/Service/dashboard-table.service'; 3 | 4 | @Component({ 5 | selector: 'app-charts', 6 | templateUrl: './charts.component.html', 7 | styleUrls: ['./charts.component.css'] 8 | }) 9 | export class ChartsComponent implements OnInit{ 10 | chart2:any; 11 | chart3:any; 12 | labels=['January', 'February', 'March', 'April', 'May','June', 'July','August','September','October','December','December']; 13 | data1:any; 14 | data2:any; 15 | data3:any; 16 | usersChart1:any; 17 | colors=["red","orange","yellow","green","blue","gray"] 18 | 19 | constructor(private dashboardService:DashboardTableService){ 20 | 21 | } 22 | ngOnInit(): void { 23 | this.dashboardService.GetAllCharts().subscribe({ 24 | next:(res:any)=>{ 25 | this.chart2=res.data.users[0].years; 26 | this.chart3=res.data.apartmentsData; 27 | let bidsDataset=res.data.bids[0].years.map((year:any,index:any)=>{ 28 | let counts =this.handleCharts(year).map((bid:any)=>{ 29 | return bid.count 30 | }) 31 | return { 32 | label: year.year, 33 | backgroundColor: this.colors[index], 34 | data: counts 35 | } 36 | }) 37 | this.usersChart1=this.handleCharts(this.chart2[0]).map((user:any)=>{ 38 | return user.count 39 | }) 40 | this.data1 = { 41 | labels: this.labels, 42 | datasets: [ 43 | { 44 | label: "2023", 45 | backgroundColor: 'rgba(151, 187, 205, 0.2)', 46 | borderColor: 'rgba(151, 187, 205, 1)', 47 | pointBackgroundColor: 'rgba(151, 187, 205, 1)', 48 | pointBorderColor: '#fff', 49 | data: this.usersChart1 50 | } 51 | ] 52 | }; 53 | this.data2 = { 54 | labels: this.labels, 55 | datasets: bidsDataset 56 | }; 57 | this.data3 = { 58 | labels: this.chart3.map((apt:any)=>{ 59 | return apt._id 60 | }), 61 | datasets: [ 62 | { 63 | label: this.chart3.map((apt:any)=>{ 64 | return apt._id 65 | }), 66 | backgroundColor: this.colors.slice(0,this.chart3.length) 67 | , 68 | data: this.chart3.map((apt:any)=>{ 69 | return apt.count 70 | }) 71 | }, 72 | ] 73 | }; 74 | }, 75 | error:(err:any)=>{ 76 | console.error(err) 77 | } 78 | }) 79 | 80 | } 81 | 82 | handleChartRef($chartRef: any) { 83 | if ($chartRef) { 84 | setTimeout(() => { 85 | $chartRef?.update(); 86 | }, 3000); 87 | } 88 | } 89 | 90 | handleCharts=(arr:any)=>{ 91 | arr.months.sort( this.compare ); 92 | let temp:any=[]; 93 | for(let i=0 ; i<12;i++){ 94 | temp[i]={month: i+1, count: 0} 95 | } 96 | for(let i=0 ; i { 102 | if ( a.month < b.month ){ 103 | return -1; 104 | } 105 | if ( a.month > b.month ){ 106 | return 1; 107 | } 108 | return 0; 109 | } 110 | 111 | } 112 | -------------------------------------------------------------------------------- /src/app/Components/bid-history/bid-history.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |

Bid History

4 |
5 |
6 |
7 |
8 |
9 | product image 10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
Current Bid:
18 |
{{ bids.currentBid }} EUR
19 |
20 |
21 |
22 |
23 |
Item id:
24 |
{{ bids.itemNumber }}
25 |
26 |
27 |
28 |
29 |
30 | Bids: 31 | {{ bids.numberOfBids }} 32 |
33 |
34 | Bidders: 35 | {{ bids.numberOfBidders }} 36 |
37 |
38 |
39 |
40 |
41 |
42 | Time left: 43 | {{ 44 | bids.timeLeft | date : "medium" 45 | }} 46 |
47 |
48 | Duration: 49 | {{ bids.duration }} 50 |
51 |
52 |
53 |
54 | Place Bid 60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 80 | 81 | 82 | 83 | 84 |
BidderBid AmountBid Time
78 | {{ item.user }} (1) 79 | {{ item["amountMoney"] }} EUR{{ item["date"] | date : "medium" }}
85 | Back 88 |
89 |
90 |
91 | -------------------------------------------------------------------------------- /src/app/Components/Profile/EditProfile/edit-profile/edit-profile.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { ActivatedRoute, Router } from '@angular/router'; 3 | import { ProfilePageService } from 'src/app/Service/profile-page.service'; 4 | import { AbstractControl, FormControl, FormGroup, ValidatorFn, Validators } from '@angular/forms'; 5 | import { NgxSpinnerService } from 'ngx-spinner'; 6 | 7 | @Component({ 8 | selector: 'app-edit-profile', 9 | templateUrl: './edit-profile.component.html', 10 | styleUrls: ['./edit-profile.component.css'], 11 | }) 12 | export class EditProfileComponent implements OnInit { 13 | User: any; 14 | validationForm:any; 15 | myForm: any; 16 | ProfileImage:any; 17 | userId: any; 18 | showPass = false; 19 | 20 | constructor( 21 | public myService: ProfilePageService, 22 | public router: Router, 23 | private route: ActivatedRoute, 24 | private spinner: NgxSpinnerService 25 | ) { 26 | this.route.parent?.paramMap.subscribe(params => { 27 | this.userId = params.get('id'); 28 | }); 29 | } 30 | 31 | // imageExtensionValidator(allowedExtensions: string[]): ValidatorFn { 32 | // return (control: AbstractControl): {[key: string]: any} | null => { 33 | // const file = control.value; 34 | // if (file) { 35 | // const fileExtension = file.name.split('.').pop().toLowerCase(); 36 | // if (allowedExtensions.indexOf(fileExtension) === -1) { 37 | // return {'invalidExtension': true}; 38 | // } 39 | // } 40 | // return null; 41 | // }; 42 | // } 43 | 44 | ngOnInit(): void { 45 | 46 | this.myService.GetUserByID(this.userId).subscribe({ 47 | next: (data) => { 48 | console.log(data); 49 | this.User = data; 50 | this.validationForm = new FormGroup({ 51 | userName: new FormControl(this.User.name, [Validators.required,Validators.minLength(3) ]), 52 | // age: new FormControl(this.User.age, [Validators.required,Validators.pattern(/^[0-9]*$/),Validators.min(18)]), 53 | // address: new FormControl(this.User.address, [Validators.required]), 54 | // phone: new FormControl(this.User.phone, [Validators.required,Validators.minLength(10),Validators.pattern(/^[0-9]*$/)]), 55 | email: new FormControl(this.User.email, [Validators.email, Validators.required]), 56 | profileImage: new FormControl( this.User.imag ), 57 | password: new FormControl(this.User.password) 58 | }); 59 | // this.validationForm.patchValue(this.User) 60 | 61 | }, 62 | error: (err) => {console.log(err)}, 63 | }); 64 | 65 | } 66 | 67 | 68 | get userName() { 69 | return this.validationForm.controls['userName']; 70 | } 71 | get age() { 72 | return this.validationForm.controls['age']; 73 | } 74 | get email() { 75 | return this.validationForm.controls['email']; 76 | } 77 | get phone() { 78 | return this.validationForm.controls['phone']; 79 | } 80 | get address() { 81 | return this.validationForm.controls['address']; 82 | } 83 | 84 | get profileImage() { 85 | return this.validationForm.controls['profileImage']; 86 | } 87 | 88 | 89 | onFileSelected(event: any){ 90 | this.ProfileImage=event.target.files[0] 91 | } 92 | 93 | updateUser(){ 94 | this.spinner.show('updateSpinner') 95 | if (this.validationForm.valid) { 96 | const fd = new FormData(); 97 | fd.append('data', JSON.stringify(this.validationForm.value)); 98 | 99 | if (this.ProfileImage instanceof File) { 100 | fd.append('profileImage', this.ProfileImage); 101 | } 102 | 103 | this.myService.UpdateUser(fd,this.userId) 104 | } 105 | } 106 | 107 | } 108 | -------------------------------------------------------------------------------- /src/app/Components/nav-bar/nav-bar.component.html: -------------------------------------------------------------------------------- 1 | 109 | -------------------------------------------------------------------------------- /src/app/Components/Profile/profile/profile.component.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |
4 | 30 | 37 | 41 | 67 |
68 |
69 | 70 |
71 |
72 | 114 | -------------------------------------------------------------------------------- /angular.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "./node_modules/@angular/cli/lib/config/schema.json", 3 | "version": 1, 4 | "newProjectRoot": "projects", 5 | "projects": { 6 | "Agoura": { 7 | "projectType": "application", 8 | "schematics": {}, 9 | "root": "", 10 | "sourceRoot": "src", 11 | "prefix": "app", 12 | "architect": { 13 | "build": { 14 | "builder": "@angular-devkit/build-angular:browser", 15 | "options": { 16 | "outputPath": "dist/agoura", 17 | "index": "src/index.html", 18 | "main": "src/main.ts", 19 | "polyfills": [ 20 | "zone.js" 21 | ], 22 | "tsConfig": "tsconfig.app.json", 23 | "assets": [ 24 | "src/favicon.ico", 25 | "src/assets" 26 | ], 27 | "styles": [ 28 | "src/styles.css", 29 | "src/scss/styles.scss", 30 | "node_modules/ngx-spinner/animations/square-jelly-box.css", 31 | "node_modules/@fortawesome/fontawesome-free/css/all.min.css", 32 | "node_modules/@fortawesome/fontawesome-free/css/solid.min.css", 33 | "node_modules/@fortawesome/fontawesome-free/css/regular.min.css", 34 | "node_modules/@fortawesome/fontawesome-free/css/brands.min.css", 35 | "node_modules/@coreui/icons/css/all.css", 36 | "node_modules/@coreui/coreui/dist/css/coreui.min.css", 37 | "node_modules/bootstrap/dist/css/bootstrap.min.css", 38 | "node_modules/animate.css/animate.min.css" 39 | ], 40 | "scripts": [ 41 | "node_modules/bootstrap/dist/js/bootstrap.js", 42 | "node_modules/@coreui/coreui/dist/js/coreui.min.js" 43 | ] 44 | }, 45 | "configurations": { 46 | "production": { 47 | "budgets": [ 48 | { 49 | "type": "initial", 50 | "maximumWarning": "10000kb", 51 | "maximumError": "5mb" 52 | }, 53 | { 54 | "type": "anyComponentStyle", 55 | "maximumWarning": "2kb", 56 | "maximumError": "4kb" 57 | } 58 | ], 59 | "outputHashing": "all" 60 | }, 61 | "development": { 62 | "buildOptimizer": false, 63 | "optimization": false, 64 | "vendorChunk": true, 65 | "extractLicenses": false, 66 | "sourceMap": true, 67 | "namedChunks": true 68 | } 69 | }, 70 | "defaultConfiguration": "production" 71 | }, 72 | "serve": { 73 | "builder": "@angular-devkit/build-angular:dev-server", 74 | "configurations": { 75 | "production": { 76 | "browserTarget": "Agoura:build:production" 77 | }, 78 | "development": { 79 | "browserTarget": "Agoura:build:development" 80 | } 81 | }, 82 | "defaultConfiguration": "development" 83 | }, 84 | "extract-i18n": { 85 | "builder": "@angular-devkit/build-angular:extract-i18n", 86 | "options": { 87 | "browserTarget": "Agoura:build" 88 | } 89 | }, 90 | "test": { 91 | "builder": "@angular-devkit/build-angular:karma", 92 | "options": { 93 | "polyfills": [ 94 | "zone.js", 95 | "zone.js/testing" 96 | ], 97 | "tsConfig": "tsconfig.spec.json", 98 | "assets": [ 99 | "src/favicon.ico", 100 | "src/assets" 101 | ], 102 | "styles": [ 103 | "@angular/material/prebuilt-themes/indigo-pink.css", 104 | "src/styles.css" 105 | ], 106 | "scripts": [] 107 | } 108 | } 109 | } 110 | } 111 | }, 112 | "cli": { 113 | "analytics": false 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /src/app/Components/Auth/sign-up/sign-up.component.html: -------------------------------------------------------------------------------- 1 |
2 | 10 |
14 |

19 | Sign up in Agoura 20 |

21 |
22 | 23 | 24 |
25 |
32 |
33 | {{ error }} 36 | 37 |
38 |
39 | 42 | 49 |
50 |
51 | Enter a vaild email address, this filed is required 55 |
56 |
57 | 60 | 67 |
68 |
69 | Enter a vaild username more than 3 characters, this filed is 72 | required 74 |
75 |
76 | 77 | 85 |
86 |
87 | Enter a vaild password more than 10 characters or numbers, this 90 | filed is required 92 |
93 |
94 | 97 | 105 |
106 |
111 | Passwords do not match 115 |
116 | 117 |
118 |
119 | You have an account? 120 | Log in 121 |
122 |
123 |
124 |
125 | -------------------------------------------------------------------------------- /src/app/app-routing.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { RouterModule, Routes } from '@angular/router'; 3 | import { ProductDetailsComponent } from './Components/product-details/product-details.component'; 4 | import { HomeComponent } from './Components/home/home.component'; 5 | import { LayoutComponent } from './Components/layout/layout.component'; 6 | import { LoginComponent } from './Components/Auth/login/login.component'; 7 | import { SignUpComponent } from './Components/Auth/sign-up/sign-up.component'; 8 | import { CheckoutComponent } from './Components/Payment/checkout/checkout.component'; 9 | import { ProfileComponent } from './Components/Profile/profile/profile.component'; 10 | import { EditProfileComponent } from './Components/Profile/EditProfile/edit-profile/edit-profile.component'; 11 | import { AboutComponent } from './Components/about/about.component'; 12 | import { CreateProductFormComponent } from './Components/create-product-form/create-product-form.component'; 13 | import { BidHistoryComponent } from './Components/bid-history/bid-history.component'; 14 | import { ForgetPasswordComponent } from './Components/forget-password/forget-password.component'; 15 | import { OtpComponent } from './Components/otp/otp.component'; 16 | import { NotfoundPageComponent } from './Components/notfound-page/notfound-page.component'; 17 | import { DefaultLayoutComponent } from './Components/dashboard/containers'; 18 | import { BidsComponent } from './Components/dashboard/views/bids/bids.component'; 19 | import { ChartsComponent } from './Components/dashboard/views/charts/charts.component'; 20 | import { DashboardBidDetailsComponent } from './Components/dashboard/views/dashboard-bid-details/dashboard-bid-details.component'; 21 | import { EditProductFormComponent } from './Components/edit-product-form/edit-product-form.component'; 22 | import { UserBidsComponent } from './Components/Profile/bids/bids.component'; 23 | import { OrdersComponent } from './Components/Profile/orders/orders.component'; 24 | import { ApartmentsComponent } from './Components/Profile/apartments/apartments.component'; 25 | import { ResetPasswordComponent } from './Components/reset-password/reset-password.component'; 26 | import { AuthGuard } from './core/guards/auth.guard'; 27 | import { ChangePassComponent } from './Components/Profile/changepass/changepass.component'; 28 | import { DashboardUsersComponent } from './Components/dashboard/views/dashboard-users/dashboard-users.component'; 29 | import { PaymentSuccessComponent } from './Components/Payment/payment-success/payment-success.component'; 30 | import { PaymentFailComponent } from './Components/Payment/payment-fail/payment-fail.component'; 31 | import { AdminAuthGuard } from './core/guards/admin-auth.guard'; 32 | import { GuestAuthGuard } from './core/guards/guest-auth.guard'; 33 | 34 | 35 | 36 | const routes: Routes = [ 37 | { path: '', redirectTo: '/home', pathMatch: 'full' }, 38 | { 39 | path: '', 40 | component: LayoutComponent, 41 | children: [ 42 | { path: 'home', component: HomeComponent }, 43 | { path: 'place/create', component: CreateProductFormComponent , canActivate:[AuthGuard] }, 44 | { path: 'place/:id', component: ProductDetailsComponent }, 45 | { path: 'place/:id/edit', component: EditProductFormComponent , canActivate:[AuthGuard] }, 46 | { path: 'place/:id/history', component: BidHistoryComponent , canActivate:[AuthGuard] }, 47 | { path: 'about', component: AboutComponent }, 48 | { path: "checkout/:id" , component : CheckoutComponent , canActivate:[AuthGuard]}, 49 | { path: "users/:id",component:ProfileComponent , canActivate:[AuthGuard] ,children:[ 50 | { path:"edit",component:EditProfileComponent , pathMatch:'full'}, 51 | { path:"bids",component:UserBidsComponent}, 52 | { path:"orders",component:OrdersComponent}, 53 | { path:"apartments",component:ApartmentsComponent}, 54 | { path:"password",component:ChangePassComponent}, 55 | ]}, 56 | ], 57 | }, 58 | { path: "dashboard" ,component:DefaultLayoutComponent,canActivate:[AdminAuthGuard] ,children:[ 59 | { path: '', redirectTo: 'charts', pathMatch: 'full' }, 60 | { path: "apartments",component:BidsComponent }, 61 | { path: "apartments/:id",component:DashboardBidDetailsComponent }, 62 | { path: "charts",component:ChartsComponent }, 63 | {path:"users",component:DashboardUsersComponent} 64 | ]}, 65 | {path : '404-NotFound', component: NotfoundPageComponent}, 66 | {path : 'login' , component : LoginComponent,canActivate:[GuestAuthGuard]}, 67 | {path : 'signup' , component: SignUpComponent,canActivate:[GuestAuthGuard]}, 68 | {path : 'forgetpassword' , component: ForgetPasswordComponent}, 69 | {path: 'otp', component: OtpComponent}, 70 | {path: 'resetpassword', component: ResetPasswordComponent}, 71 | { path: "PaymentFail" , component : PaymentFailComponent , canActivate:[AuthGuard]}, 72 | { path: "PaymentSuccess" , component : PaymentSuccessComponent , canActivate:[AuthGuard]}, 73 | {path : '**', component: NotfoundPageComponent}, 74 | 75 | ]; 76 | 77 | 78 | @NgModule({ 79 | imports: [RouterModule.forRoot(routes)], 80 | exports: [RouterModule], 81 | }) 82 | export class AppRoutingModule {} 83 | -------------------------------------------------------------------------------- /src/app/Components/dashboard/containers/default-layout/default-header/default-header.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 15 | 30 | 31 | 51 | 52 | 58 | 59 | 60 | 165 | 166 | -------------------------------------------------------------------------------- /src/app/Components/Profile/profile/profile.component.css: -------------------------------------------------------------------------------- 1 | 2 | @import url(https://fonts.googleapis.com/css?family=Quicksand:300,400|Lato:400,300|Coda|Open+Sans); 3 | 4 | a { 5 | text-decoration: none; 6 | color: #3498db; 7 | } 8 | .content-profile-page { 9 | font-family: "Open sans", sans-serif; 10 | margin: 1em auto; 11 | width:80% 12 | } 13 | 14 | .cardat { 15 | background: #fff; 16 | border-radius: 0.3rem; 17 | box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2); 18 | border: .1em solid rgba(0, 0, 0, 0.2); 19 | margin-bottom: 1em; 20 | } 21 | 22 | .profile-user-page .img-user-profile { 23 | margin: 0 auto; 24 | text-align: center; 25 | width:100% 26 | } 27 | .profile-user-page .img-user-profile .profile-bgHome { 28 | border-bottom: .2em solid #f5f5f5; 29 | width: 100%; 30 | height: 25em; 31 | } 32 | .profile-user-page .img-user-profile .avatar { 33 | margin: 0 auto; 34 | background: #fff; 35 | width: 8em; 36 | height: 8em; 37 | padding: 0.25em; 38 | border-radius: .4em; 39 | margin-top: -10em; 40 | box-shadow: 0 0 .1em rgba(0, 0, 0, 0.35); 41 | transition: .5s all ease-in-out; 42 | } 43 | 44 | .profile-user-page button { 45 | position: absolute; 46 | font-size: 13px; 47 | font-weight: bold; 48 | cursor: pointer; 49 | width: 7em; 50 | background: #3498db; 51 | border: 1px solid #2487c9; 52 | color: #fff; 53 | outline: none; 54 | border-radius: 0 .6em .6em 0; 55 | padding: .80em; 56 | } 57 | 58 | .profile-user-page button:hover { 59 | background: #51a7e0; 60 | transition: background .2s ease-in-out; 61 | border: 1px solid #2487c9; 62 | } 63 | .profile-user-page .user-profile-data, .profile-user-page .description-profile { 64 | text-align: center; 65 | padding: 0 1.5em; 66 | } 67 | .profile-user-page .user-profile-data h1 { 68 | font-family: "Lato", sans-serif; 69 | margin-top: 0.35em; 70 | color: #292f33; 71 | margin-bottom: 0; 72 | } 73 | .profile-user-page .user-profile-data p { 74 | font-family: "Lato", sans-serif; 75 | color: #8899a6; 76 | font-size: 1.1em; 77 | margin-top: 0; 78 | margin-bottom: 0.5em; 79 | } 80 | .profile-user-page .description-profile { 81 | color: #75787b; 82 | font-size: 0.98em; 83 | } 84 | .profile-user-page .data-user { 85 | font-family: "Quicksand", sans-serif; 86 | margin-bottom: 0; 87 | cursor: pointer; 88 | padding: 0; 89 | list-style: none; 90 | display: table; 91 | width: 100.15%; 92 | } 93 | .profile-user-page .data-user li { 94 | margin: 0; 95 | padding: 0; 96 | width: 33.33334%; 97 | display: table-cell; 98 | text-align: center; 99 | border-left: 0.1em solid transparent; 100 | } 101 | .profile-user-page .data-user li:first-child { 102 | border-left: 0; 103 | } 104 | .profile-user-page .data-user li:first-child a { 105 | border-bottom-left-radius: 0.3rem; 106 | } 107 | .profile-user-page .data-user li:last-child a { 108 | border-bottom-right-radius: 0.3rem; 109 | } 110 | .profile-user-page .data-user li a, .profile-user-page .data-user li strong { 111 | display: block; 112 | } 113 | .profile-user-page .data-user li a { 114 | background-color: #f7f7f7; 115 | border-top: 1px solid rgba(242,242,242,0.5); 116 | border-bottom: .2em solid #f7f7f7; 117 | box-shadow: inset 0 1px 0 rgba(255,255,255,0.4),0 1px 1px rgba(255,255,255,0.4); 118 | padding: .93em 0; 119 | color: #46494c; 120 | } 121 | .profile-user-page .data-user li a strong, .profile-user-page .data-user li a span { 122 | font-weight: 600; 123 | line-height: 1; 124 | } 125 | .profile-user-page .data-user li a strong { 126 | font-size: 2em; 127 | } 128 | .profile-user-page .data-user li a span { 129 | color: #717a7e; 130 | } 131 | .profile-user-page .data-user li a:hover { 132 | background: rgba(0, 0, 0, 0.05); 133 | border-bottom: .2em solid #3498db; 134 | color: #3498db; 135 | } 136 | .profile-user-page .data-user li a:hover span { 137 | color: #3498db; 138 | } 139 | 140 | 141 | .cardat { 142 | --bg: #f7f7f8; 143 | --hover-bg: #cccc; 144 | --hover-text: black; 145 | max-width: 18ch; 146 | max-height: 18ch; 147 | text-align: center; 148 | background: var(--bg); 149 | border-radius: 5px; 150 | position: relative; 151 | overflow: hidden; 152 | transition: .3s cubic-bezier(.6,.4,0,1),transform .15s ease; 153 | display: flex; 154 | flex-direction: column; 155 | justify-content: center; 156 | align-items: center; 157 | gap: 1em; 158 | } 159 | 160 | .parent{ 161 | margin-top: -90px; 162 | } 163 | 164 | .cardat__body { 165 | color: #464853; 166 | line-height: 1.5em; 167 | font-size: 1em; 168 | } 169 | .cardat img{ 170 | width: 100%; 171 | aspect-ratio: 1/1; 172 | } 173 | 174 | .cardat > :not(span) { 175 | transition: .3s cubic-bezier(.6,.4,0,1); 176 | } 177 | 178 | .cardat > strong { 179 | display: block; 180 | font-size: 1.4rem; 181 | letter-spacing: -.035em; 182 | } 183 | 184 | .cardat span { 185 | position: absolute; 186 | inset: 0; 187 | width: 100%; 188 | height: 50%; 189 | display: flex; 190 | justify-content: center; 191 | align-items: center; 192 | color: var(--hover-text); 193 | border-radius: 5px; 194 | font-weight: bold; 195 | top: 100%; 196 | transition: all .3s cubic-bezier(.6,.4,0,1); 197 | cursor: pointer; 198 | } 199 | 200 | .cardat:hover span { 201 | top: 50%; 202 | font-size: 1.2em; 203 | } 204 | 205 | .cardat:hover span { 206 | background: var(--hover-bg); 207 | } 208 | 209 | 210 | .imageInfo{ 211 | font-size: small; 212 | color: #8899a6; 213 | margin-top: 5%; 214 | } 215 | -------------------------------------------------------------------------------- /src/app/Components/create-product-form/create-product-form.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, Input, OnChanges } from '@angular/core'; 2 | import { FormControl, FormGroup , Validators ,FormBuilder, FormArray} from '@angular/forms'; 3 | import { ActivatedRoute, Router } from '@angular/router'; 4 | import { BidsService } from 'src/app/Service/bids.service'; 5 | import { CreateBidService } from 'src/app/Service/create-bid.service'; 6 | 7 | @Component({ 8 | selector: 'app-create-product-form', 9 | templateUrl: './create-product-form.component.html', 10 | styleUrls: ['./create-product-form.component.css'] 11 | }) 12 | export class CreateProductFormComponent implements OnChanges{ 13 | @Input("edit") edit=false; 14 | files!:FileList; 15 | validationForm!:FormGroup; 16 | step:number; 17 | id!:any; 18 | public constructor(private fb:FormBuilder,private myService:CreateBidService,private myBidService:BidsService,private router:Router,private route:ActivatedRoute){ 19 | this.step=1; 20 | this.validationForm = fb.group({ 21 | title: new FormControl(null,[Validators.required, Validators.minLength(5)]), 22 | category:new FormControl(null,[Validators.required]), 23 | address: fb.group({ 24 | country:new FormControl(null,[Validators.required, Validators.minLength(5)]), 25 | city:new FormControl(null,[Validators.required, Validators.minLength(5)]), 26 | street:new FormControl(null,[Validators.required, Validators.minLength(5)]), 27 | zipCode:new FormControl(null,[Validators.required,Validators.pattern("^[0-9]{5,9}$")]), 28 | }), 29 | features: fb.group({ 30 | bedRooms:new FormControl(null,[Validators.required, Validators.min(1),Validators.pattern("^[0-9]+$")]), 31 | baths:new FormControl(null,[Validators.required, Validators.min(1),Validators.pattern("^[0-9]+$")]), 32 | area:new FormControl(null,[Validators.required, Validators.min(1),Validators.pattern("^[0-9]+$")]), 33 | kitchen:new FormControl(null,[Validators.required, Validators.min(1),Validators.pattern("^[0-9]+$")]), 34 | guests:new FormControl(null,[Validators.required, Validators.min(1),Validators.pattern("^[0-9]+$")]), 35 | }), 36 | aboutPlace: new FormControl(null,[Validators.required, Validators.minLength(100)]), 37 | startBid: new FormControl(null,[Validators.required,Validators.min(1),Validators.pattern("^[0-9]+$")]), 38 | duration:new FormControl(null,[Validators.required,Validators.min(7),Validators.max(30),Validators.pattern("^[0-9]+$")]), 39 | agreeToTerms:new FormControl(null,[Validators.required]), 40 | images:new FormControl([],[Validators.required,Validators.min(1),]) 41 | }); 42 | } 43 | ngOnChanges(){ 44 | let bidId=this.route.snapshot.params["id"] 45 | 46 | if(this.edit){ 47 | this.myBidService.GetPendingBidById(bidId).subscribe({ 48 | next:(res:any)=>{ 49 | console.log(res) 50 | if(res.success){ 51 | this.id=res.data.appartment._id 52 | this.validationForm.patchValue(res.data.appartment); 53 | // this.validationForm.markAsDirty() 54 | this.validationForm.controls["images"].removeValidators 55 | } 56 | }, 57 | error:(err)=>{ 58 | console.log(err) 59 | } 60 | }) 61 | } 62 | } 63 | get title () { 64 | return this.validationForm.controls["title"]; 65 | } 66 | get category () { 67 | return this.validationForm.controls["category"]; 68 | } 69 | get aboutPlace () { 70 | return this.validationForm.controls["aboutPlace"]; 71 | } 72 | get duration () { 73 | return this.validationForm.controls["duration"]; 74 | } 75 | get startBid () { 76 | return this.validationForm.controls["startBid"]; 77 | } 78 | get agreeToTerms () { 79 | return this.validationForm.controls["agreeToTerms"]; 80 | } 81 | get country () { 82 | return this.validationForm.controls["address"].get("country"); 83 | } 84 | get city () { 85 | return this.validationForm.controls["address"].get("city"); 86 | } 87 | get street () { 88 | return this.validationForm.controls["address"].get("street"); 89 | } 90 | get zipCode () { 91 | return this.validationForm.controls["address"].get("zipCode"); 92 | } 93 | get bedRooms () { 94 | return this.validationForm.controls["features"].get("bedRooms"); 95 | } 96 | get baths () { 97 | return this.validationForm.controls["features"].get("baths"); 98 | } 99 | get area () { 100 | return this.validationForm.controls["features"].get("area"); 101 | } 102 | get kitchen () { 103 | return this.validationForm.controls["features"].get("kitchen"); 104 | } 105 | get guests () { 106 | return this.validationForm.controls["features"].get("guests"); 107 | } 108 | get images () { 109 | return this.validationForm.controls["images"] as FormArray; 110 | } 111 | 112 | onFileSelected(event: any) { 113 | this.files = event.target.files; 114 | } 115 | 116 | send(){ 117 | 118 | console.log(this.validationForm) 119 | if(this.validationForm.valid && !this.edit){ 120 | let formData=new FormData() 121 | formData.append("data",JSON.stringify(this.validationForm.value)) 122 | if(this.files){ 123 | for(let i=0;i{ 130 | if(res.success){ 131 | this.router.navigateByUrl(`home`) 132 | console.log(res) 133 | } 134 | }, 135 | error:(err)=>{console.log(err)} 136 | } 137 | ); 138 | console.log("created success",bid) 139 | } 140 | if(this.validationForm.valid && this.edit){ 141 | this.myBidService.updateBidById(this.id,this.validationForm.value).subscribe( 142 | { 143 | next:(res:any)=>{ 144 | if(res.success){ 145 | this.router.navigateByUrl(`home`) 146 | console.log(res) 147 | } 148 | }, 149 | error:(err)=>{console.log(err)} 150 | } 151 | ); 152 | console.log("created success") 153 | } 154 | } 155 | 156 | get firstPageValid(){ 157 | return this.title.valid && this.country?.valid && this.city?.valid && this.street?.valid && this.zipCode?.valid 158 | } 159 | 160 | next() { 161 | console.log(`step ${this.step} form ${this.validationForm.valid}`) 162 | this.step++; 163 | } 164 | prev() { 165 | console.log(`step ${this.step} form ${this.validationForm.valid}`) 166 | this.step--; 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /src/app/icons/icon-subset.ts: -------------------------------------------------------------------------------- 1 | import { 2 | cibCcAmex, 3 | cibCcApplePay, 4 | cibCcMastercard, 5 | cibCcPaypal, 6 | cibCcStripe, 7 | cibCcVisa, 8 | cibFacebook, 9 | cibGoogle, 10 | cibLinkedin, 11 | cibSkype, 12 | cibTwitter, 13 | cifBr, 14 | cifEs, 15 | cifFr, 16 | cifIn, 17 | cifPl, 18 | cifUs, 19 | cilAlignCenter, 20 | cilAlignLeft, 21 | cilAlignRight, 22 | cilApplicationsSettings, 23 | cilArrowBottom, 24 | cilArrowRight, 25 | cilArrowTop, 26 | cilBasket, 27 | cilBell, 28 | cilBold, 29 | cilBookmark, 30 | cilCalculator, 31 | cilCalendar, 32 | cilChart, 33 | cilChartPie, 34 | cilCheck, 35 | cilChevronLeft, 36 | cilChevronRight, 37 | cilCloudDownload, 38 | cilCode, 39 | cilCommentSquare, 40 | cilCreditCard, 41 | cilCursor, 42 | cilDollar, 43 | cilDrop, 44 | cilEnvelopeClosed, 45 | cilEnvelopeOpen, 46 | cilFile, 47 | cilHome, 48 | cilInbox, 49 | cilIndentDecrease, 50 | cilIndentIncrease, 51 | cilItalic, 52 | cilJustifyCenter, 53 | cilLayers, 54 | cilList, 55 | cilListNumbered, 56 | cilLocationPin, 57 | cilLockLocked, 58 | cilMagnifyingGlass, 59 | cilMap, 60 | cilMediaPlay, 61 | cilMenu, 62 | cilMoon, 63 | cilNotes, 64 | cilOptions, 65 | cilPaperclip, 66 | cilPaperPlane, 67 | cilPen, 68 | cilPencil, 69 | cilPeople, 70 | cilPrint, 71 | cilPuzzle, 72 | cilReportSlash, 73 | cilSave, 74 | cilSettings, 75 | cilShare, 76 | cilShareAll, 77 | cilShareBoxed, 78 | cilSpeech, 79 | cilSpeedometer, 80 | cilSpreadsheet, 81 | cilStar, 82 | cilSun, 83 | cilTags, 84 | cilTask, 85 | cilTrash, 86 | cilUnderline, 87 | cilUser, 88 | cilUserFemale, 89 | cilUserFollow, 90 | cilUserUnfollow, 91 | } from '@coreui/icons'; 92 | 93 | export const iconSubset = { 94 | cibCcAmex, 95 | cibCcApplePay, 96 | cibCcMastercard, 97 | cibCcPaypal, 98 | cibCcStripe, 99 | cibCcVisa, 100 | cibFacebook, 101 | cibGoogle, 102 | cibLinkedin, 103 | cibSkype, 104 | cibTwitter, 105 | cifBr, 106 | cifEs, 107 | cifFr, 108 | cifIn, 109 | cifPl, 110 | cifUs, 111 | cilAlignCenter, 112 | cilAlignLeft, 113 | cilAlignRight, 114 | cilApplicationsSettings, 115 | cilArrowBottom, 116 | cilArrowRight, 117 | cilArrowTop, 118 | cilBasket, 119 | cilBell, 120 | cilBold, 121 | cilBookmark, 122 | cilCalculator, 123 | cilCalendar, 124 | cilChart, 125 | cilChartPie, 126 | cilCheck, 127 | cilChevronLeft, 128 | cilChevronRight, 129 | cilCloudDownload, 130 | cilCode, 131 | cilCommentSquare, 132 | cilCreditCard, 133 | cilCursor, 134 | cilDollar, 135 | cilDrop, 136 | cilEnvelopeClosed, 137 | cilEnvelopeOpen, 138 | cilFile, 139 | cilHome, 140 | cilInbox, 141 | cilIndentDecrease, 142 | cilIndentIncrease, 143 | cilItalic, 144 | cilJustifyCenter, 145 | cilLayers, 146 | cilList, 147 | cilListNumbered, 148 | cilLocationPin, 149 | cilLockLocked, 150 | cilMagnifyingGlass, 151 | cilMap, 152 | cilMediaPlay, 153 | cilMenu, 154 | cilMoon, 155 | cilNotes, 156 | cilOptions, 157 | cilPaperclip, 158 | cilPaperPlane, 159 | cilPen, 160 | cilPencil, 161 | cilPeople, 162 | cilPrint, 163 | cilPuzzle, 164 | cilReportSlash, 165 | cilSave, 166 | cilSettings, 167 | cilShare, 168 | cilShareAll, 169 | cilShareBoxed, 170 | cilSpeech, 171 | cilSpeedometer, 172 | cilSpreadsheet, 173 | cilStar, 174 | cilSun, 175 | cilTags, 176 | cilTask, 177 | cilTrash, 178 | cilUnderline, 179 | cilUser, 180 | cilUserFemale, 181 | cilUserFollow, 182 | cilUserUnfollow, 183 | }; 184 | 185 | export enum IconSubset { 186 | cibCcAmex = 'cibCcAmex', 187 | cibCcApplePay = 'cibCcApplePay', 188 | cibCcMastercard = 'cibCcMastercard', 189 | cibCcPaypal = 'cibCcPaypal', 190 | cibCcStripe = 'cibCcStripe', 191 | cibCcVisa = 'cibCcVisa', 192 | cibFacebook = 'cibFacebook', 193 | cibGoogle = 'cibGoogle', 194 | cibLinkedin = 'cibLinkedin', 195 | cibSkype = 'cibSkype', 196 | cibTwitter = 'cibTwitter', 197 | cifBr = 'cifBr', 198 | cifEs = 'cifEs', 199 | cifFr = 'cifFr', 200 | cifIn = 'cifIn', 201 | cifPl = 'cifPl', 202 | cifUs = 'cifUs', 203 | cilAlignCenter = 'cilAlignCenter', 204 | cilAlignLeft = 'cilAlignLeft', 205 | cilAlignRight = 'cilAlignRight', 206 | cilApplicationsSettings = 'cilApplicationsSettings', 207 | cilArrowBottom = 'cilArrowBottom', 208 | cilArrowRight = 'cilArrowRight', 209 | cilArrowTop = 'cilArrowTop', 210 | cilBasket = 'cilBasket', 211 | cilBell = 'cilBell', 212 | cilBold = 'cilBold', 213 | cilBookmark = 'cilBookmark', 214 | cilCalculator = 'cilCalculator', 215 | cilCalendar = 'cilCalendar', 216 | cilChart = 'cilChart', 217 | cilChartPie = 'cilChartPie', 218 | cilCheck='cilCheck', 219 | cilChevronLeft = 'cilChevronLeft', 220 | cilChevronRight = 'cilChevronRight', 221 | cilCloudDownload = 'cilCloudDownload', 222 | cilCode = 'cilCode', 223 | cilCommentSquare = 'cilCommentSquare', 224 | cilCreditCard = 'cilCreditCard', 225 | cilCursor = 'cilCursor', 226 | cilDollar = 'cilDollar', 227 | cilDrop = 'cilDrop', 228 | cilEnvelopeClosed = 'cilEnvelopeClosed', 229 | cilEnvelopeOpen = 'cilEnvelopeOpen', 230 | cilFile = 'cilFile', 231 | cilHome = 'cilHome', 232 | cilInbox = 'cilInbox', 233 | cilIndentDecrease = 'cilIndentDecrease', 234 | cilIndentIncrease = 'cilIndentIncrease', 235 | cilItalic = 'cilItalic', 236 | cilJustifyCenter = 'cilJustifyCenter', 237 | cilLayers = 'cilLayers', 238 | cilList = 'cilList', 239 | cilListNumbered = 'cilListNumbered', 240 | cilLocationPin = 'cilLocationPin', 241 | cilLockLocked = 'cilLockLocked', 242 | cilMagnifyingGlass = 'cilMagnifyingGlass', 243 | cilMap = 'cilMap', 244 | cilMediaPlay = 'cilMediaPlay', 245 | cilMenu = 'cilMenu', 246 | cilMoon = 'cilMoon', 247 | cilNotes = 'cilNotes', 248 | cilOptions = 'cilOptions', 249 | cilPaperclip = 'cilPaperclip', 250 | cilPaperPlane = 'cilPaperPlane', 251 | cilPen = 'cilPen', 252 | cilPencil = 'cilPencil', 253 | cilPeople = 'cilPeople', 254 | cilPrint = 'cilPrint', 255 | cilPuzzle = 'cilPuzzle', 256 | cilReportSlash = 'cilReportSlash', 257 | cilSave = 'cilSave', 258 | cilSettings = 'cilSettings', 259 | cilShare = 'cilShare', 260 | cilShareAll = 'cilShareAll', 261 | cilShareBoxed = 'cilShareBoxed', 262 | cilSpeech = 'cilSpeech', 263 | cilSpeedometer = 'cilSpeedometer', 264 | cilSpreadsheet = 'cilSpreadsheet', 265 | cilStar = 'cilStar', 266 | cilSun = 'cilSun', 267 | cilTags = 'cilTags', 268 | cilTask = 'cilTask', 269 | cilTrash = 'cilTrash', 270 | cilUnderline = 'cilUnderline', 271 | cilUser = 'cilUser', 272 | cilUserFemale = 'cilUserFemale', 273 | cilUserFollow = 'cilUserFollow', 274 | cilUserUnfollow = 'cilUserUnfollow', 275 | } 276 | --------------------------------------------------------------------------------