Sostituito frontend angular new con frontend angular. Sostituito frontend angular con frontend angular old
This commit is contained in:
@@ -1,20 +0,0 @@
|
||||
# Frontend Angular Dockerfile
|
||||
FROM node:20-alpine
|
||||
|
||||
# Set working directory
|
||||
WORKDIR /app
|
||||
|
||||
# Copy package files
|
||||
COPY package*.json ./
|
||||
|
||||
# Install dependencies
|
||||
RUN npm install
|
||||
|
||||
# Copy application code
|
||||
COPY . .
|
||||
|
||||
# Expose port
|
||||
EXPOSE 4200
|
||||
|
||||
# Start development server
|
||||
CMD ["npm", "run", "dev", "--", "--host", "0.0.0.0"]
|
||||
@@ -1,20 +0,0 @@
|
||||
<div align="center">
|
||||
<img width="1200" height="475" alt="GHBanner" src="https://github.com/user-attachments/assets/0aa67016-6eaf-458a-adb2-6e31a0763ed6" />
|
||||
</div>
|
||||
|
||||
# Run and deploy your AI Studio app
|
||||
|
||||
This contains everything you need to run your app locally.
|
||||
|
||||
View your app in AI Studio: https://ai.studio/apps/7d951078-743c-4db5-ac20-6a2c625411e7
|
||||
|
||||
## Run Locally
|
||||
|
||||
**Prerequisites:** Node.js
|
||||
|
||||
|
||||
1. Install dependencies:
|
||||
`npm install`
|
||||
2. Set the `GEMINI_API_KEY` in [.env.local](.env.local) to your Gemini API key
|
||||
3. Run the app:
|
||||
`npm run dev`
|
||||
@@ -1,94 +0,0 @@
|
||||
{
|
||||
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
|
||||
"version": 1,
|
||||
"cli": {
|
||||
"packageManager": "npm",
|
||||
"schematicCollections": [
|
||||
"angular-eslint"
|
||||
]
|
||||
},
|
||||
"newProjectRoot": "projects",
|
||||
"projects": {
|
||||
"app": {
|
||||
"projectType": "application",
|
||||
"schematics": {},
|
||||
"root": "",
|
||||
"sourceRoot": "src",
|
||||
"prefix": "app",
|
||||
"architect": {
|
||||
"build": {
|
||||
"builder": "@angular/build:application",
|
||||
"options": {
|
||||
"define": {
|
||||
"GEMINI_API_KEY": "'YOUR_GEMINI_API_KEY'"
|
||||
},
|
||||
"browser": "src/main.ts",
|
||||
"tsConfig": "tsconfig.app.json",
|
||||
"assets": [
|
||||
{
|
||||
"glob": "**/*",
|
||||
"input": "public"
|
||||
}
|
||||
],
|
||||
"styles": [
|
||||
"src/styles.css"
|
||||
]
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"fileReplacements": [
|
||||
{
|
||||
"replace": "src/environments/environment.ts",
|
||||
"with": "src/environments/environment.prod.ts"
|
||||
}
|
||||
],
|
||||
"budgets": [
|
||||
{
|
||||
"type": "initial",
|
||||
"maximumWarning": "500kB",
|
||||
"maximumError": "1MB"
|
||||
},
|
||||
{
|
||||
"type": "anyComponentStyle",
|
||||
"maximumWarning": "4kB",
|
||||
"maximumError": "8kB"
|
||||
}
|
||||
],
|
||||
"outputHashing": "all"
|
||||
},
|
||||
"development": {
|
||||
"optimization": false,
|
||||
"extractLicenses": false,
|
||||
"sourceMap": true
|
||||
}
|
||||
},
|
||||
"defaultConfiguration": "production"
|
||||
},
|
||||
"serve": {
|
||||
"builder": "@angular/build:dev-server",
|
||||
"configurations": {
|
||||
"production": {
|
||||
"buildTarget": "app:build:production"
|
||||
},
|
||||
"development": {
|
||||
"buildTarget": "app:build:development"
|
||||
}
|
||||
},
|
||||
"defaultConfiguration": "development"
|
||||
},
|
||||
"test": {
|
||||
"builder": "@angular/build:unit-test"
|
||||
},
|
||||
"lint": {
|
||||
"builder": "@angular-eslint/builder:lint",
|
||||
"options": {
|
||||
"lintFilePatterns": [
|
||||
"src/**/*.ts",
|
||||
"src/**/*.html"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"name": "ScommettiApp",
|
||||
"description": "A social betting and challenge platform to compete with friends and join communities.",
|
||||
"requestFramePermissions": ["geolocation"]
|
||||
}
|
||||
Generated
-12338
File diff suppressed because it is too large
Load Diff
@@ -1,46 +0,0 @@
|
||||
{
|
||||
"name": "amici-scommesse",
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "ng serve",
|
||||
"build": "ng build",
|
||||
"preview": "ng serve --configuration=production"
|
||||
},
|
||||
"dependencies": {
|
||||
"@angular/cdk": "^21.0.0",
|
||||
"@angular/common": "^21.0.0",
|
||||
"@angular/compiler": "^21.0.0",
|
||||
"@angular/core": "^21.0.0",
|
||||
"@angular/forms": "^21.0.0",
|
||||
"@angular/material": "^21.0.0",
|
||||
"@angular/platform-browser": "^21.0.0",
|
||||
"@angular/platform-server": "^21.0.0",
|
||||
"@angular/router": "^21.0.0",
|
||||
"@angular/ssr": "^21.0.0",
|
||||
"@google/genai": "^1.27.0",
|
||||
"express": "^5.1.0",
|
||||
"keycloak-js": "^26.2.3",
|
||||
"motion": "^12.23.24",
|
||||
"rxjs": "~7.8.0",
|
||||
"tslib": "^2.3.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular/build": "^21.0.0",
|
||||
"@angular/cli": "^21.0.0",
|
||||
"@angular/compiler-cli": "^21.0.0",
|
||||
"@tailwindcss/postcss": "^4.1.12",
|
||||
"@types/express": "^5.0.1",
|
||||
"@types/node": "^20.17.19",
|
||||
"angular-eslint": "21.1.0",
|
||||
"cross-env": "^10.1.0",
|
||||
"eslint": "^9.39.1",
|
||||
"jsdom": "^27.0.0",
|
||||
"postcss": "^8.5.3",
|
||||
"tailwindcss": "^4.1.12",
|
||||
"typescript": "~5.9.2",
|
||||
"typescript-eslint": "8.47.0",
|
||||
"vitest": "^4.0.0"
|
||||
}
|
||||
}
|
||||
@@ -1,156 +0,0 @@
|
||||
<div class="min-h-screen pb-32">
|
||||
<header class="sticky top-0 z-50 bg-background/80 backdrop-blur-md flex justify-between items-center px-6 py-4">
|
||||
<div class="flex items-center gap-4">
|
||||
<button class="w-10 h-10 rounded-full flex items-center justify-center hover:bg-surface-container transition-colors" [routerLink]="['/']">
|
||||
<mat-icon>arrow_back</mat-icon>
|
||||
</button>
|
||||
<h1 class="font-headline font-black tracking-tight text-xl text-primary">The Arena</h1>
|
||||
</div>
|
||||
<div class="flex items-center gap-3">
|
||||
<button (click)="editChallenge()" class="w-10 h-10 rounded-full flex items-center justify-center hover:bg-surface-container transition-colors text-primary">
|
||||
<mat-icon>edit</mat-icon>
|
||||
</button>
|
||||
<mat-icon class="text-on-surface-variant cursor-pointer">search</mat-icon>
|
||||
<div class="w-8 h-8 rounded-full bg-primary-container overflow-hidden">
|
||||
<img src="https://picsum.photos/seed/user/100/100" class="w-full h-full object-cover" alt="User Avatar">
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="max-w-xl mx-auto px-6 pt-8 space-y-8">
|
||||
@if (isLoading()) {
|
||||
<div class="flex flex-col items-center justify-center py-20">
|
||||
<div class="w-12 h-12 border-4 border-primary border-t-transparent rounded-full animate-spin"></div>
|
||||
<p class="mt-4 text-on-surface-variant font-medium">Loading arena details...</p>
|
||||
</div>
|
||||
} @else if (bet(); as data) {
|
||||
<!-- Hero Section -->
|
||||
<section class="space-y-4">
|
||||
<div class="flex justify-between items-start">
|
||||
<div class="space-y-1">
|
||||
<span class="inline-flex items-center px-3 py-1 rounded-full bg-secondary-container text-secondary text-xs font-semibold tracking-wide uppercase">
|
||||
{{ data.status }}
|
||||
</span>
|
||||
<h2 class="text-3xl font-headline font-extrabold">{{ data.title }}</h2>
|
||||
</div>
|
||||
<div class="bg-surface-container p-3 rounded-2xl flex flex-col items-center">
|
||||
<span class="text-[10px] font-bold text-on-surface-variant uppercase tracking-widest">Stake</span>
|
||||
<span class="text-xl font-headline font-black text-primary">€{{ data.stake }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-on-surface-variant text-lg">{{ data.description || 'No description provided.' }}</p>
|
||||
</section>
|
||||
|
||||
<!-- Stats -->
|
||||
<div class="grid grid-cols-2 gap-4">
|
||||
<div class="bg-surface-container-low p-6 rounded-2xl flex flex-col gap-1 border border-black/5">
|
||||
<span class="text-xs font-medium text-on-surface-variant">Start Date</span>
|
||||
<span class="text-sm font-headline font-bold">{{ data.startDate | date:'mediumDate' }}</span>
|
||||
</div>
|
||||
<div class="bg-surface-container-low p-6 rounded-2xl flex flex-col gap-1 border border-black/5">
|
||||
<span class="text-xs font-medium text-on-surface-variant">Visibility</span>
|
||||
<span class="text-sm font-headline font-bold">{{ data.isPublic ? 'Public' : 'Private' }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Participants -->
|
||||
<section class="space-y-4">
|
||||
<div class="flex items-center justify-between">
|
||||
<h3 class="font-headline font-bold">Participants</h3>
|
||||
<span class="text-sm font-medium text-primary">{{ data.participants.length }} Joined</span>
|
||||
</div>
|
||||
<div class="flex flex-wrap gap-3">
|
||||
@for (p of data.participants; track $index) {
|
||||
<div class="flex flex-col items-center gap-1">
|
||||
<div class="relative">
|
||||
@if ($any(p.user)?.avatarUrl) {
|
||||
<img [src]="$any(p.user).avatarUrl" class="h-12 w-12 rounded-full ring-2 ring-primary/20 object-cover" [alt]="$any(p.user).name">
|
||||
} @else {
|
||||
<div class="h-12 w-12 rounded-full ring-2 ring-primary/20 bg-primary-container/20 flex items-center justify-center">
|
||||
<mat-icon class="text-primary">person</mat-icon>
|
||||
</div>
|
||||
}
|
||||
@if (p.role === 'OBSERVER') {
|
||||
<div class="absolute -bottom-1 -right-1 bg-surface-container rounded-full p-0.5 shadow-sm">
|
||||
<mat-icon class="text-[10px] text-on-surface-variant">visibility</mat-icon>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
<span class="text-[10px] font-medium text-on-surface-variant">{{ $any(p.user)?.name || 'Utente' }}</span>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</section>
|
||||
} @else {
|
||||
<div class="flex flex-col items-center justify-center py-20 text-center">
|
||||
<mat-icon class="text-6xl text-on-surface-variant/20 mb-4">search_off</mat-icon>
|
||||
<h3 class="text-xl font-headline font-bold">Challenge Not Found</h3>
|
||||
<p class="text-on-surface-variant mt-2">The challenge you're looking for doesn't exist or has been removed.</p>
|
||||
<button class="mt-6 text-primary font-bold" [routerLink]="['/']">Go Back Home</button>
|
||||
</div>
|
||||
}
|
||||
|
||||
<!-- Live Standings -->
|
||||
<section class="bg-surface-container p-6 rounded-2xl space-y-6 border border-black/5">
|
||||
<div class="flex items-center justify-between">
|
||||
<h3 class="font-headline font-bold">Live Standings</h3>
|
||||
<mat-icon class="text-primary">leaderboard</mat-icon>
|
||||
</div>
|
||||
<div class="space-y-5">
|
||||
<div class="space-y-2">
|
||||
<div class="flex justify-between items-end">
|
||||
<span class="text-sm font-bold">You (Alex)</span>
|
||||
<span class="text-xs font-medium text-on-surface-variant">16,402 / 20,000</span>
|
||||
</div>
|
||||
<div class="h-3 w-full bg-surface-container-highest rounded-full overflow-hidden">
|
||||
<div class="h-full bg-gradient-to-r from-primary to-primary-container rounded-full" style="width: 82%"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="space-y-2">
|
||||
<div class="flex justify-between items-end">
|
||||
<span class="text-sm font-medium">Sarah J.</span>
|
||||
<span class="text-xs font-medium text-on-surface-variant">18,210 / 20,000</span>
|
||||
</div>
|
||||
<div class="h-3 w-full bg-surface-container-highest rounded-full overflow-hidden">
|
||||
<div class="h-full bg-tertiary rounded-full" style="width: 91%"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Stats Bento -->
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<div class="bg-surface-container-low p-6 rounded-2xl flex items-center gap-4 border border-black/5">
|
||||
<div class="w-12 h-12 rounded-full bg-tertiary-container/20 flex items-center justify-center">
|
||||
<mat-icon class="text-tertiary">local_fire_department</mat-icon>
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-xs font-medium text-on-surface-variant">Hot Streak</p>
|
||||
<p class="text-lg font-headline font-bold">3 Wins</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-surface-container-low p-6 rounded-2xl flex items-center gap-4 border border-black/5">
|
||||
<div class="w-12 h-12 rounded-full bg-secondary-container/20 flex items-center justify-center">
|
||||
<mat-icon class="text-secondary">groups</mat-icon>
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-xs font-medium text-on-surface-variant">Activity Level</p>
|
||||
<p class="text-lg font-headline font-bold">High</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<!-- Action Buttons -->
|
||||
<div class="fixed bottom-0 left-0 w-full p-6 bg-background/80 backdrop-blur-xl z-40 border-t border-black/5">
|
||||
<div class="max-w-xl mx-auto flex flex-col gap-3">
|
||||
<button class="w-full py-4 bg-gradient-to-r from-primary to-primary-container text-white font-headline font-bold rounded-full shadow-lg active:scale-95 transition-transform">
|
||||
Update Progress
|
||||
</button>
|
||||
<button class="w-full py-4 bg-surface-container-highest text-on-surface font-headline font-bold rounded-full active:scale-95 transition-transform flex items-center justify-center gap-2">
|
||||
<mat-icon>person_add</mat-icon>
|
||||
Invite Friends
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,48 +0,0 @@
|
||||
import {ChangeDetectionStrategy, Component, inject, signal, OnInit} from '@angular/core';
|
||||
import {CommonModule} from '@angular/common';
|
||||
import {MatIconModule} from '@angular/material/icon';
|
||||
import {RouterModule, Router, ActivatedRoute} from '@angular/router';
|
||||
import {BetService} from '../../services/bet';
|
||||
import {Bet} from '../../models/data.models';
|
||||
|
||||
@Component({
|
||||
selector: 'app-challenge-detail',
|
||||
standalone: true,
|
||||
imports: [CommonModule, MatIconModule, RouterModule],
|
||||
templateUrl: './challenge-detail.html',
|
||||
styleUrl: './challenge-detail.css',
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class ChallengeDetail implements OnInit {
|
||||
private router = inject(Router);
|
||||
private route = inject(ActivatedRoute);
|
||||
private betService = inject(BetService);
|
||||
|
||||
challengeId = this.route.snapshot.paramMap.get('id');
|
||||
bet = signal<Bet | null>(null);
|
||||
isLoading = signal(true);
|
||||
|
||||
ngOnInit() {
|
||||
if (this.challengeId) {
|
||||
this.betService.getBetById(this.challengeId).subscribe({
|
||||
next: (data) => {
|
||||
this.bet.set(data);
|
||||
this.isLoading.set(false);
|
||||
},
|
||||
error: (err) => {
|
||||
console.error('Error loading bet:', err);
|
||||
this.isLoading.set(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
editChallenge() {
|
||||
const data = this.bet();
|
||||
if (data) {
|
||||
this.router.navigate(['/create-bet'], {
|
||||
state: { bet: data }
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
import { InjectionToken } from '@angular/core';
|
||||
import Keycloak from 'keycloak-js';
|
||||
|
||||
export const KEYCLOAK_INSTANCE = new InjectionToken<Keycloak>('KeycloakInstance');
|
||||
@@ -1,18 +0,0 @@
|
||||
export interface SuccessResponse<T = any> {
|
||||
success: boolean;
|
||||
message?: string;
|
||||
data: T;
|
||||
timestamp: string;
|
||||
}
|
||||
|
||||
export interface ErrorDetail {
|
||||
field?: string;
|
||||
message: string;
|
||||
}
|
||||
|
||||
export interface ErrorResponse {
|
||||
success: boolean;
|
||||
message: string;
|
||||
errors?: ErrorDetail[];
|
||||
timestamp: string;
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
export const environment = {
|
||||
production: true,
|
||||
apiUrl: '', // da compilare in produzione
|
||||
keycloakUrl: '',
|
||||
keycloakRealm: 'scommettiapp',
|
||||
keycloakClientId: 'scommetti-frontend',
|
||||
};
|
||||
@@ -1,35 +0,0 @@
|
||||
/* To learn more about Typescript configuration file: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html. */
|
||||
/* To learn more about Angular compiler options: https://angular.dev/reference/configs/angular-compiler-options. */
|
||||
{
|
||||
"compileOnSave": false,
|
||||
"compilerOptions": {
|
||||
"strict": true,
|
||||
"noImplicitOverride": true,
|
||||
"noPropertyAccessFromIndexSignature": true,
|
||||
"noImplicitReturns": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"skipLibCheck": true,
|
||||
"isolatedModules": true,
|
||||
"resolveJsonModule": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"experimentalDecorators": true,
|
||||
"importHelpers": true,
|
||||
"target": "ES2022",
|
||||
"module": "preserve"
|
||||
},
|
||||
"angularCompilerOptions": {
|
||||
"enableI18nLegacyMessageIdFormat": false,
|
||||
"strictInjectionParameters": true,
|
||||
"strictInputAccessModifiers": true,
|
||||
"strictTemplates": true
|
||||
},
|
||||
"files": [],
|
||||
"references": [
|
||||
{
|
||||
"path": "./tsconfig.app.json"
|
||||
},
|
||||
{
|
||||
"path": "./tsconfig.spec.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user