Compare commits
102 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ed3d9bf52e | |||
| b3cae6e3a9 | |||
| a37b45f5b6 | |||
| 036ba39a5f | |||
| ac9d62d284 | |||
| 8f836c6d80 | |||
| e8c308adf8 | |||
| 42116be9a6 | |||
| eee7958bce | |||
| d5584ebf0a | |||
| 6a1ed5abeb | |||
| e483bc4e57 | |||
| f1354c2db3 | |||
| bd0d15bbf0 | |||
| 90749ea55e | |||
| ff7039a80b | |||
| fb467d52d9 | |||
| f09d5a0f11 | |||
| 9367f5e7b3 | |||
| a9e13c3af3 | |||
| 5e6b03356c | |||
| 3eacc4976d | |||
| 4e9a4cf428 | |||
| 4dbf052437 | |||
| 2c8cb490a4 | |||
| a229835b1a | |||
| 99b4e0ea35 | |||
| 3e6aae68d2 | |||
| a1446f39ca | |||
| 4d82abd8a1 | |||
| 6bf8230fa3 | |||
| 9e729202f0 | |||
| b08753ebae | |||
| 467cb3f886 | |||
| ec9af0c2f3 | |||
| c66eb37326 | |||
| 92b85377c2 | |||
| 9ce8d3051b | |||
| cf3aea320e | |||
| 402825d2c0 | |||
| ebdb76bf7e | |||
| ad4a530fb3 | |||
| 169abddce7 | |||
| d9af61889a | |||
| ce5cc5880b | |||
| af04b03bb7 | |||
| b551659a69 | |||
| 90243bc671 | |||
| 83f68a3029 | |||
| f13541ccab | |||
| 4df957ddfb | |||
| 8e56b0eced | |||
| ee09331baf | |||
| 697f1e8490 | |||
| 97bafde4a4 | |||
| 917a0dcc9f | |||
| f6b2e1dbac | |||
| 2d370b5630 | |||
| 5ca9954b0b | |||
| 6ab77fe800 | |||
| 4d5380b40c | |||
| ffe2ca4f26 | |||
| d40fbd9a20 | |||
| 092dd3b2b1 | |||
| dc4c751210 | |||
| d5716b69a8 | |||
| d43aa9270d | |||
| 53f6667035 | |||
| 0a1e30cf69 | |||
| fa937f33bf | |||
| c46a437cb2 | |||
| 5441783eb2 | |||
| 95d46d7811 | |||
| 1f8a0e1584 | |||
| 75251601ae | |||
| d2742f095f | |||
| cf1df4700e | |||
| fdb4cf119b | |||
| 8dc66363ce | |||
| 350313917c | |||
| 0428a69d15 | |||
| 9346bf9ee3 | |||
| 57b82b4d3f | |||
| 373daa876a | |||
| d0f519f4b1 | |||
| 822e22690b | |||
| 5be67500c6 | |||
| 13ad5d369c | |||
| 69c2991c54 | |||
| 6ec656fde1 | |||
| ef2afb0b58 | |||
| 491c57b061 | |||
| 085a3a507a | |||
| 870032a733 | |||
| d7a6d363f8 | |||
| 692e2aef82 | |||
| 95f92229a4 | |||
| c24103a2ad | |||
| 2a7678d57b | |||
| c15e8d9a57 | |||
| 3ea7d5e68a | |||
| 2c0381964c |
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"plugins": {
|
||||
"@tailwindcss/postcss": {}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
# Using Android gitignore template: https://github.com/github/gitignore/blob/HEAD/Android.gitignore
|
||||
|
||||
# Built application files
|
||||
*.apk
|
||||
*.aar
|
||||
*.ap_
|
||||
*.aab
|
||||
|
||||
# Files for the ART/Dalvik VM
|
||||
*.dex
|
||||
|
||||
# Java class files
|
||||
*.class
|
||||
|
||||
# Generated files
|
||||
bin/
|
||||
gen/
|
||||
out/
|
||||
# Uncomment the following line in case you need and you don't have the release build type files in your app
|
||||
# release/
|
||||
|
||||
# Gradle files
|
||||
.gradle/
|
||||
build/
|
||||
|
||||
# Local configuration file (sdk path, etc)
|
||||
local.properties
|
||||
|
||||
# Proguard folder generated by Eclipse
|
||||
proguard/
|
||||
|
||||
# Log Files
|
||||
*.log
|
||||
|
||||
# Android Studio Navigation editor temp files
|
||||
.navigation/
|
||||
|
||||
# Android Studio captures folder
|
||||
captures/
|
||||
|
||||
# IntelliJ
|
||||
*.iml
|
||||
.idea/workspace.xml
|
||||
.idea/tasks.xml
|
||||
.idea/gradle.xml
|
||||
.idea/assetWizardSettings.xml
|
||||
.idea/dictionaries
|
||||
.idea/libraries
|
||||
# Android Studio 3 in .gitignore file.
|
||||
.idea/caches
|
||||
.idea/modules.xml
|
||||
# Comment next line if keeping position of elements in Navigation Editor is relevant for you
|
||||
.idea/navEditor.xml
|
||||
|
||||
# Keystore files
|
||||
# Uncomment the following lines if you do not want to check your keystore files in.
|
||||
#*.jks
|
||||
#*.keystore
|
||||
|
||||
# External native build folder generated in Android Studio 2.2 and later
|
||||
.externalNativeBuild
|
||||
.cxx/
|
||||
|
||||
# Google Services (e.g. APIs or Firebase)
|
||||
# google-services.json
|
||||
|
||||
# Freeline
|
||||
freeline.py
|
||||
freeline/
|
||||
freeline_project_description.json
|
||||
|
||||
# fastlane
|
||||
fastlane/report.xml
|
||||
fastlane/Preview.html
|
||||
fastlane/screenshots
|
||||
fastlane/test_output
|
||||
fastlane/readme.md
|
||||
|
||||
# Version control
|
||||
vcs.xml
|
||||
|
||||
# lint
|
||||
lint/intermediates/
|
||||
lint/generated/
|
||||
lint/outputs/
|
||||
lint/tmp/
|
||||
# lint/reports/
|
||||
|
||||
# Android Profiling
|
||||
*.hprof
|
||||
|
||||
# Cordova plugins for Capacitor
|
||||
capacitor-cordova-android-plugins
|
||||
|
||||
# Copied web assets
|
||||
app/src/main/assets/public
|
||||
|
||||
# Generated Config files
|
||||
app/src/main/assets/capacitor.config.json
|
||||
app/src/main/assets/capacitor.plugins.json
|
||||
app/src/main/res/xml/config.xml
|
||||
@@ -0,0 +1,2 @@
|
||||
/build/*
|
||||
!/build/.npmkeep
|
||||
@@ -0,0 +1,54 @@
|
||||
apply plugin: 'com.android.application'
|
||||
|
||||
android {
|
||||
namespace = "com.mesc.beready"
|
||||
compileSdk = rootProject.ext.compileSdkVersion
|
||||
defaultConfig {
|
||||
applicationId "com.mesc.beready"
|
||||
minSdkVersion rootProject.ext.minSdkVersion
|
||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
aaptOptions {
|
||||
// Files and dirs to omit from the packaged assets dir, modified to accommodate modern web apps.
|
||||
// Default: https://android.googlesource.com/platform/frameworks/base/+/282e181b58cf72b6ca770dc7ca5f91f135444502/tools/aapt/AaptAssets.cpp#61
|
||||
ignoreAssetsPattern = '!.svn:!.git:!.ds_store:!*.scc:.*:!CVS:!thumbs.db:!picasa.ini:!*~'
|
||||
}
|
||||
}
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
repositories {
|
||||
flatDir{
|
||||
dirs '../capacitor-cordova-android-plugins/src/main/libs', 'libs'
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation fileTree(include: ['*.jar'], dir: 'libs')
|
||||
implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion"
|
||||
implementation "androidx.coordinatorlayout:coordinatorlayout:$androidxCoordinatorLayoutVersion"
|
||||
implementation "androidx.core:core-splashscreen:$coreSplashScreenVersion"
|
||||
implementation project(':capacitor-android')
|
||||
testImplementation "junit:junit:$junitVersion"
|
||||
androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion"
|
||||
androidTestImplementation "androidx.test.espresso:espresso-core:$androidxEspressoCoreVersion"
|
||||
implementation project(':capacitor-cordova-android-plugins')
|
||||
}
|
||||
|
||||
apply from: 'capacitor.build.gradle'
|
||||
|
||||
try {
|
||||
def servicesJSON = file('google-services.json')
|
||||
if (servicesJSON.text) {
|
||||
apply plugin: 'com.google.gms.google-services'
|
||||
}
|
||||
} catch(Exception e) {
|
||||
logger.info("google-services.json not found, google-services plugin not applied. Push Notifications won't work")
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
// DO NOT EDIT THIS FILE! IT IS GENERATED EACH TIME "capacitor update" IS RUN
|
||||
|
||||
android {
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_21
|
||||
targetCompatibility JavaVersion.VERSION_21
|
||||
}
|
||||
}
|
||||
|
||||
apply from: "../capacitor-cordova-android-plugins/cordova.variables.gradle"
|
||||
dependencies {
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
if (hasProperty('postBuildExtras')) {
|
||||
postBuildExtras()
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
# Add project specific ProGuard rules here.
|
||||
# You can control the set of applied configuration files using the
|
||||
# proguardFiles setting in build.gradle.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# If your project uses WebView with JS, uncomment the following
|
||||
# and specify the fully qualified class name to the JavaScript interface
|
||||
# class:
|
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||
# public *;
|
||||
#}
|
||||
|
||||
# Uncomment this to preserve the line number information for
|
||||
# debugging stack traces.
|
||||
#-keepattributes SourceFile,LineNumberTable
|
||||
|
||||
# If you keep the line number information, uncomment this to
|
||||
# hide the original source file name.
|
||||
#-renamesourcefileattribute SourceFile
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.getcapacitor.myapp;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import android.content.Context;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import androidx.test.platform.app.InstrumentationRegistry;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
/**
|
||||
* Instrumented test, which will execute on an Android device.
|
||||
*
|
||||
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
|
||||
*/
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class ExampleInstrumentedTest {
|
||||
|
||||
@Test
|
||||
public void useAppContext() throws Exception {
|
||||
// Context of the app under test.
|
||||
Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
|
||||
|
||||
assertEquals("com.getcapacitor.app", appContext.getPackageName());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/AppTheme">
|
||||
|
||||
<activity
|
||||
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|smallestScreenSize|screenLayout|uiMode|navigation|density"
|
||||
android:name=".MainActivity"
|
||||
android:label="@string/title_activity_main"
|
||||
android:theme="@style/AppTheme.NoActionBarLaunch"
|
||||
android:launchMode="singleTask"
|
||||
android:exported="true">
|
||||
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
|
||||
</activity>
|
||||
|
||||
<provider
|
||||
android:name="androidx.core.content.FileProvider"
|
||||
android:authorities="${applicationId}.fileprovider"
|
||||
android:exported="false"
|
||||
android:grantUriPermissions="true">
|
||||
<meta-data
|
||||
android:name="android.support.FILE_PROVIDER_PATHS"
|
||||
android:resource="@xml/file_paths"></meta-data>
|
||||
</provider>
|
||||
</application>
|
||||
|
||||
<!-- Permissions -->
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.CAMERA"/>
|
||||
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
|
||||
</manifest>
|
||||
@@ -0,0 +1,5 @@
|
||||
package com.mesc.beready;
|
||||
|
||||
import com.getcapacitor.BridgeActivity;
|
||||
|
||||
public class MainActivity extends BridgeActivity {}
|
||||
|
After Width: | Height: | Size: 7.5 KiB |
|
After Width: | Height: | Size: 3.9 KiB |
|
After Width: | Height: | Size: 9.0 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 7.7 KiB |
|
After Width: | Height: | Size: 4.0 KiB |
|
After Width: | Height: | Size: 9.6 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 17 KiB |
@@ -0,0 +1,34 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:aapt="http://schemas.android.com/aapt"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportHeight="108"
|
||||
android:viewportWidth="108">
|
||||
<path
|
||||
android:fillType="evenOdd"
|
||||
android:pathData="M32,64C32,64 38.39,52.99 44.13,50.95C51.37,48.37 70.14,49.57 70.14,49.57L108.26,87.69L108,109.01L75.97,107.97L32,64Z"
|
||||
android:strokeColor="#00000000"
|
||||
android:strokeWidth="1">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:endX="78.5885"
|
||||
android:endY="90.9159"
|
||||
android:startX="48.7653"
|
||||
android:startY="61.0927"
|
||||
android:type="linear">
|
||||
<item
|
||||
android:color="#44000000"
|
||||
android:offset="0.0" />
|
||||
<item
|
||||
android:color="#00000000"
|
||||
android:offset="1.0" />
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:fillType="nonZero"
|
||||
android:pathData="M66.94,46.02L66.94,46.02C72.44,50.07 76,56.61 76,64L32,64C32,56.61 35.56,50.11 40.98,46.06L36.18,41.19C35.45,40.45 35.45,39.3 36.18,38.56C36.91,37.81 38.05,37.81 38.78,38.56L44.25,44.05C47.18,42.57 50.48,41.71 54,41.71C57.48,41.71 60.78,42.57 63.68,44.05L69.11,38.56C69.84,37.81 70.98,37.81 71.71,38.56C72.44,39.3 72.44,40.45 71.71,41.19L66.94,46.02ZM62.94,56.92C64.08,56.92 65,56.01 65,54.88C65,53.76 64.08,52.85 62.94,52.85C61.8,52.85 60.88,53.76 60.88,54.88C60.88,56.01 61.8,56.92 62.94,56.92ZM45.06,56.92C46.2,56.92 47.13,56.01 47.13,54.88C47.13,53.76 46.2,52.85 45.06,52.85C43.92,52.85 43,53.76 43,54.88C43,56.01 43.92,56.92 45.06,56.92Z"
|
||||
android:strokeColor="#00000000"
|
||||
android:strokeWidth="1" />
|
||||
</vector>
|
||||
@@ -0,0 +1,170 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportHeight="108"
|
||||
android:viewportWidth="108">
|
||||
<path
|
||||
android:fillColor="#26A69A"
|
||||
android:pathData="M0,0h108v108h-108z" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M9,0L9,108"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,0L19,108"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M29,0L29,108"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M39,0L39,108"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M49,0L49,108"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M59,0L59,108"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M69,0L69,108"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M79,0L79,108"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M89,0L89,108"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M99,0L99,108"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,9L108,9"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,19L108,19"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,29L108,29"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,39L108,39"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,49L108,49"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,59L108,59"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,69L108,69"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,79L108,79"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,89L108,89"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,99L108,99"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,29L89,29"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,39L89,39"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,49L89,49"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,59L89,59"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,69L89,69"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,79L89,79"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M29,19L29,89"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M39,19L39,89"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M49,19L49,89"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M59,19L59,89"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M69,19L69,89"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M79,19L79,89"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
</vector>
|
||||
|
After Width: | Height: | Size: 3.9 KiB |
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".MainActivity">
|
||||
|
||||
<WebView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@color/ic_launcher_background"/>
|
||||
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
|
||||
</adaptive-icon>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@color/ic_launcher_background"/>
|
||||
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
|
||||
</adaptive-icon>
|
||||
|
After Width: | Height: | Size: 2.7 KiB |
|
After Width: | Height: | Size: 3.4 KiB |
|
After Width: | Height: | Size: 4.2 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 2.1 KiB |
|
After Width: | Height: | Size: 2.7 KiB |
|
After Width: | Height: | Size: 3.9 KiB |
|
After Width: | Height: | Size: 4.9 KiB |
|
After Width: | Height: | Size: 6.4 KiB |
|
After Width: | Height: | Size: 6.5 KiB |
|
After Width: | Height: | Size: 9.6 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 9.2 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 16 KiB |
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="ic_launcher_background">#FFFFFF</color>
|
||||
</resources>
|
||||
@@ -0,0 +1,7 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<resources>
|
||||
<string name="app_name">BeReadyFrontend</string>
|
||||
<string name="title_activity_main">BeReadyFrontend</string>
|
||||
<string name="package_name">com.mesc.beready</string>
|
||||
<string name="custom_url_scheme">com.mesc.beready</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
<!-- Base application theme. -->
|
||||
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
|
||||
<!-- Customize your theme here. -->
|
||||
<item name="colorPrimary">@color/colorPrimary</item>
|
||||
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
|
||||
<item name="colorAccent">@color/colorAccent</item>
|
||||
</style>
|
||||
|
||||
<style name="AppTheme.NoActionBar" parent="Theme.AppCompat.DayNight.NoActionBar">
|
||||
<item name="windowActionBar">false</item>
|
||||
<item name="windowNoTitle">true</item>
|
||||
<item name="android:background">@null</item>
|
||||
</style>
|
||||
|
||||
|
||||
<style name="AppTheme.NoActionBarLaunch" parent="Theme.SplashScreen">
|
||||
<item name="android:background">@drawable/splash</item>
|
||||
</style>
|
||||
</resources>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<paths xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<external-path name="my_images" path="." />
|
||||
<cache-path name="my_cache_images" path="." />
|
||||
</paths>
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.getcapacitor.myapp;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* Example local unit test, which will execute on the development machine (host).
|
||||
*
|
||||
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
|
||||
*/
|
||||
public class ExampleUnitTest {
|
||||
|
||||
@Test
|
||||
public void addition_isCorrect() throws Exception {
|
||||
assertEquals(4, 2 + 2);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||
|
||||
buildscript {
|
||||
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:8.13.0'
|
||||
classpath 'com.google.gms:google-services:4.4.4'
|
||||
|
||||
// NOTE: Do not place your application dependencies here; they belong
|
||||
// in the individual module build.gradle files
|
||||
}
|
||||
}
|
||||
|
||||
apply from: "variables.gradle"
|
||||
|
||||
allprojects {
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
}
|
||||
}
|
||||
|
||||
task clean(type: Delete) {
|
||||
delete rootProject.buildDir
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
// DO NOT EDIT THIS FILE! IT IS GENERATED EACH TIME "capacitor update" IS RUN
|
||||
include ':capacitor-android'
|
||||
project(':capacitor-android').projectDir = new File('../node_modules/@capacitor/android/capacitor')
|
||||
@@ -0,0 +1,22 @@
|
||||
# Project-wide Gradle settings.
|
||||
|
||||
# IDE (e.g. Android Studio) users:
|
||||
# Gradle settings configured through the IDE *will override*
|
||||
# any settings specified in this file.
|
||||
|
||||
# For more details on how to configure your build environment visit
|
||||
# http://www.gradle.org/docs/current/userguide/build_environment.html
|
||||
|
||||
# Specifies the JVM arguments used for the daemon process.
|
||||
# The setting is particularly useful for tweaking memory settings.
|
||||
org.gradle.jvmargs=-Xmx1536m
|
||||
|
||||
# When configured, Gradle will run in incubating parallel mode.
|
||||
# This option should only be used with decoupled projects. More details, visit
|
||||
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
|
||||
# org.gradle.parallel=true
|
||||
|
||||
# AndroidX package structure to make it clearer which packages are bundled with the
|
||||
# Android operating system, and which are packaged with your app's APK
|
||||
# https://developer.android.com/topic/libraries/support-library/androidx-rn
|
||||
android.useAndroidX=true
|
||||
@@ -0,0 +1,7 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-all.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
@@ -0,0 +1,251 @@
|
||||
#!/bin/sh
|
||||
|
||||
#
|
||||
# Copyright © 2015-2021 the original authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
#
|
||||
# Gradle start up script for POSIX generated by Gradle.
|
||||
#
|
||||
# Important for running:
|
||||
#
|
||||
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
|
||||
# noncompliant, but you have some other compliant shell such as ksh or
|
||||
# bash, then to run this script, type that shell name before the whole
|
||||
# command line, like:
|
||||
#
|
||||
# ksh Gradle
|
||||
#
|
||||
# Busybox and similar reduced shells will NOT work, because this script
|
||||
# requires all of these POSIX shell features:
|
||||
# * functions;
|
||||
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
|
||||
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
|
||||
# * compound commands having a testable exit status, especially «case»;
|
||||
# * various built-in commands including «command», «set», and «ulimit».
|
||||
#
|
||||
# Important for patching:
|
||||
#
|
||||
# (2) This script targets any POSIX shell, so it avoids extensions provided
|
||||
# by Bash, Ksh, etc; in particular arrays are avoided.
|
||||
#
|
||||
# The "traditional" practice of packing multiple parameters into a
|
||||
# space-separated string is a well documented source of bugs and security
|
||||
# problems, so this is (mostly) avoided, by progressively accumulating
|
||||
# options in "$@", and eventually passing that to Java.
|
||||
#
|
||||
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
|
||||
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
|
||||
# see the in-line comments for details.
|
||||
#
|
||||
# There are tweaks for specific operating systems such as AIX, CygWin,
|
||||
# Darwin, MinGW, and NonStop.
|
||||
#
|
||||
# (3) This script is generated from the Groovy template
|
||||
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# within the Gradle project.
|
||||
#
|
||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
|
||||
# Resolve links: $0 may be a link
|
||||
app_path=$0
|
||||
|
||||
# Need this for daisy-chained symlinks.
|
||||
while
|
||||
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
|
||||
[ -h "$app_path" ]
|
||||
do
|
||||
ls=$( ls -ld "$app_path" )
|
||||
link=${ls#*' -> '}
|
||||
case $link in #(
|
||||
/*) app_path=$link ;; #(
|
||||
*) app_path=$APP_HOME$link ;;
|
||||
esac
|
||||
done
|
||||
|
||||
# This is normally unused
|
||||
# shellcheck disable=SC2034
|
||||
APP_BASE_NAME=${0##*/}
|
||||
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
|
||||
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD=maximum
|
||||
|
||||
warn () {
|
||||
echo "$*"
|
||||
} >&2
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
} >&2
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
nonstop=false
|
||||
case "$( uname )" in #(
|
||||
CYGWIN* ) cygwin=true ;; #(
|
||||
Darwin* ) darwin=true ;; #(
|
||||
MSYS* | MINGW* ) msys=true ;; #(
|
||||
NONSTOP* ) nonstop=true ;;
|
||||
esac
|
||||
|
||||
CLASSPATH="\\\"\\\""
|
||||
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD=$JAVA_HOME/jre/sh/java
|
||||
else
|
||||
JAVACMD=$JAVA_HOME/bin/java
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD=java
|
||||
if ! command -v java >/dev/null 2>&1
|
||||
then
|
||||
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||
case $MAX_FD in #(
|
||||
max*)
|
||||
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC2039,SC3045
|
||||
MAX_FD=$( ulimit -H -n ) ||
|
||||
warn "Could not query maximum file descriptor limit"
|
||||
esac
|
||||
case $MAX_FD in #(
|
||||
'' | soft) :;; #(
|
||||
*)
|
||||
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC2039,SC3045
|
||||
ulimit -n "$MAX_FD" ||
|
||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||
esac
|
||||
fi
|
||||
|
||||
# Collect all arguments for the java command, stacking in reverse order:
|
||||
# * args from the command line
|
||||
# * the main class name
|
||||
# * -classpath
|
||||
# * -D...appname settings
|
||||
# * --module-path (only if needed)
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
|
||||
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if "$cygwin" || "$msys" ; then
|
||||
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
||||
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
|
||||
|
||||
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
||||
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
for arg do
|
||||
if
|
||||
case $arg in #(
|
||||
-*) false ;; # don't mess with options #(
|
||||
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
|
||||
[ -e "$t" ] ;; #(
|
||||
*) false ;;
|
||||
esac
|
||||
then
|
||||
arg=$( cygpath --path --ignore --mixed "$arg" )
|
||||
fi
|
||||
# Roll the args list around exactly as many times as the number of
|
||||
# args, so each arg winds up back in the position where it started, but
|
||||
# possibly modified.
|
||||
#
|
||||
# NB: a `for` loop captures its iteration list before it begins, so
|
||||
# changing the positional parameters here affects neither the number of
|
||||
# iterations, nor the values presented in `arg`.
|
||||
shift # remove old arg
|
||||
set -- "$@" "$arg" # push replacement arg
|
||||
done
|
||||
fi
|
||||
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Collect all arguments for the java command:
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
||||
# and any embedded shellness will be escaped.
|
||||
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
|
||||
# treated as '${Hostname}' itself on the command line.
|
||||
|
||||
set -- \
|
||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||
-classpath "$CLASSPATH" \
|
||||
-jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
|
||||
"$@"
|
||||
|
||||
# Stop when "xargs" is not available.
|
||||
if ! command -v xargs >/dev/null 2>&1
|
||||
then
|
||||
die "xargs is not available"
|
||||
fi
|
||||
|
||||
# Use "xargs" to parse quoted args.
|
||||
#
|
||||
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
|
||||
#
|
||||
# In Bash we could simply go:
|
||||
#
|
||||
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
|
||||
# set -- "${ARGS[@]}" "$@"
|
||||
#
|
||||
# but POSIX shell has neither arrays nor command substitution, so instead we
|
||||
# post-process each arg (as a line of input to sed) to backslash-escape any
|
||||
# character that might be a shell metacharacter, then use eval to reverse
|
||||
# that process (while maintaining the separation between arguments), and wrap
|
||||
# the whole thing up as a single "set" statement.
|
||||
#
|
||||
# This will of course break if any of these variables contains a newline or
|
||||
# an unmatched quote.
|
||||
#
|
||||
|
||||
eval "set -- $(
|
||||
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
|
||||
xargs -n1 |
|
||||
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
|
||||
tr '\n' ' '
|
||||
)" '"$@"'
|
||||
|
||||
exec "$JAVACMD" "$@"
|
||||
@@ -0,0 +1,94 @@
|
||||
@rem
|
||||
@rem Copyright 2015 the original author or authors.
|
||||
@rem
|
||||
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@rem you may not use this file except in compliance with the License.
|
||||
@rem You may obtain a copy of the License at
|
||||
@rem
|
||||
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||
@rem
|
||||
@rem Unless required by applicable law or agreed to in writing, software
|
||||
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@rem See the License for the specific language governing permissions and
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
@rem SPDX-License-Identifier: Apache-2.0
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%"=="" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%"=="" set DIRNAME=.
|
||||
@rem This is normally unused
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if %ERRORLEVEL% equ 0 goto execute
|
||||
|
||||
echo. 1>&2
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
|
||||
echo. 1>&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||
echo location of your Java installation. 1>&2
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto execute
|
||||
|
||||
echo. 1>&2
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
|
||||
echo. 1>&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||
echo location of your Java installation. 1>&2
|
||||
|
||||
goto fail
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=
|
||||
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if %ERRORLEVEL% equ 0 goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
set EXIT_CODE=%ERRORLEVEL%
|
||||
if %EXIT_CODE% equ 0 set EXIT_CODE=1
|
||||
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
|
||||
exit /b %EXIT_CODE%
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
||||
@@ -0,0 +1,5 @@
|
||||
include ':app'
|
||||
include ':capacitor-cordova-android-plugins'
|
||||
project(':capacitor-cordova-android-plugins').projectDir = new File('./capacitor-cordova-android-plugins/')
|
||||
|
||||
apply from: 'capacitor.settings.gradle'
|
||||
@@ -0,0 +1,16 @@
|
||||
ext {
|
||||
minSdkVersion = 24
|
||||
compileSdkVersion = 36
|
||||
targetSdkVersion = 36
|
||||
androidxActivityVersion = '1.11.0'
|
||||
androidxAppCompatVersion = '1.7.1'
|
||||
androidxCoordinatorLayoutVersion = '1.3.0'
|
||||
androidxCoreVersion = '1.17.0'
|
||||
androidxFragmentVersion = '1.8.9'
|
||||
coreSplashScreenVersion = '1.2.0'
|
||||
androidxWebkitVersion = '1.14.0'
|
||||
junitVersion = '4.13.2'
|
||||
androidxJunitVersion = '1.3.0'
|
||||
androidxEspressoCoreVersion = '3.7.0'
|
||||
cordovaAndroidVersion = '14.0.1'
|
||||
}
|
||||
@@ -50,7 +50,40 @@
|
||||
}
|
||||
],
|
||||
"styles": [
|
||||
"src/styles.css"
|
||||
"src/styles.css",
|
||||
{
|
||||
"input": "node_modules/@ionic/angular/css/core.css"
|
||||
},
|
||||
{
|
||||
"input": "node_modules/@ionic/angular/css/normalize.css"
|
||||
},
|
||||
{
|
||||
"input": "node_modules/@ionic/angular/css/structure.css"
|
||||
},
|
||||
{
|
||||
"input": "node_modules/@ionic/angular/css/typography.css"
|
||||
},
|
||||
{
|
||||
"input": "node_modules/@ionic/angular/css/display.css"
|
||||
},
|
||||
{
|
||||
"input": "node_modules/@ionic/angular/css/padding.css"
|
||||
},
|
||||
{
|
||||
"input": "node_modules/@ionic/angular/css/float-elements.css"
|
||||
},
|
||||
{
|
||||
"input": "node_modules/@ionic/angular/css/text-alignment.css"
|
||||
},
|
||||
{
|
||||
"input": "node_modules/@ionic/angular/css/text-transformation.css"
|
||||
},
|
||||
{
|
||||
"input": "node_modules/@ionic/angular/css/flex-utils.css"
|
||||
},
|
||||
{
|
||||
"input": "src/theme/variables.css"
|
||||
}
|
||||
]
|
||||
},
|
||||
"configurations": {
|
||||
@@ -91,8 +124,46 @@
|
||||
},
|
||||
"extract-i18n": {
|
||||
"builder": "@angular/build:extract-i18n"
|
||||
},
|
||||
"ionic-cordova-serve": {
|
||||
"builder": "@ionic/angular-toolkit:cordova-serve",
|
||||
"options": {
|
||||
"cordovaBuildTarget": "BeReadyFrontend:ionic-cordova-build",
|
||||
"devServerTarget": "BeReadyFrontend:serve"
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"cordovaBuildTarget": "BeReadyFrontend:ionic-cordova-build:production",
|
||||
"devServerTarget": "BeReadyFrontend:serve:production"
|
||||
}
|
||||
}
|
||||
},
|
||||
"ionic-cordova-build": {
|
||||
"builder": "@ionic/angular-toolkit:cordova-build",
|
||||
"options": {
|
||||
"browserTarget": "BeReadyFrontend:build"
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"browserTarget": "BeReadyFrontend:build:production"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"cli": {
|
||||
"schematicCollections": [
|
||||
"@ionic/angular-toolkit"
|
||||
],
|
||||
"analytics": "e8e950b1-4841-478c-ba40-4e4328545e20"
|
||||
},
|
||||
"schematics": {
|
||||
"@ionic/angular-toolkit:component": {
|
||||
"styleext": "scss"
|
||||
},
|
||||
"@ionic/angular-toolkit:page": {
|
||||
"styleext": "scss"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
import type { CapacitorConfig } from '@capacitor/cli';
|
||||
|
||||
const config: CapacitorConfig = {
|
||||
appId: 'com.mesc.beready',
|
||||
appName: 'BeReadyFrontend',
|
||||
webDir: 'dist/BeReadyFrontend/browser',
|
||||
};
|
||||
|
||||
export default config;
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"name": "ionic-app",
|
||||
"app_id": "",
|
||||
"type": "angular-standalone",
|
||||
"integrations": {}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
additionalProperties:
|
||||
fileNaming: kebab-case
|
||||
modelPropertyNaming: camelCase
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"$schema": "./node_modules/@openapitools/openapi-generator-cli/config.schema.json",
|
||||
"spaces": 2,
|
||||
"generator-cli": {
|
||||
"version": "7.20.0"
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,8 @@
|
||||
"ng": "ng",
|
||||
"start": "ng serve",
|
||||
"build": "ng build",
|
||||
"watch": "ng build --watch --configuration development"
|
||||
"watch": "ng build --watch --configuration development",
|
||||
"openapi": "rimraf src/app/services/api && openapi-generator-cli generate -i http://localhost:5235/swagger/v1/swagger.json -g typescript-angular -o src/app/services/api -c openapi-generator.yaml"
|
||||
},
|
||||
"prettier": {
|
||||
"printWidth": 100,
|
||||
@@ -27,7 +28,20 @@
|
||||
"@angular/forms": "^20.3.0",
|
||||
"@angular/platform-browser": "^20.3.0",
|
||||
"@angular/router": "^20.3.0",
|
||||
"@capacitor/android": "^8.3.0",
|
||||
"@capacitor/angular": "^2.0.3",
|
||||
"@capacitor/core": "latest",
|
||||
"@ionic/angular": "^8.8.1",
|
||||
"@microsoft/signalr": "^10.0.0",
|
||||
"@openapitools/openapi-generator-cli": "^2.30.2",
|
||||
"@tailwindcss/postcss": "^4.2.1",
|
||||
"browser-image-compression": "^2.0.2",
|
||||
"jwt-decode": "^4.0.0",
|
||||
"moment": "^2.30.1",
|
||||
"postcss": "^8.5.8",
|
||||
"rimraf": "^6.1.3",
|
||||
"rxjs": "~7.8.0",
|
||||
"tailwindcss": "^4.2.1",
|
||||
"tslib": "^2.3.0",
|
||||
"zone.js": "~0.15.0"
|
||||
},
|
||||
@@ -35,6 +49,8 @@
|
||||
"@angular/build": "^20.3.9",
|
||||
"@angular/cli": "^20.3.9",
|
||||
"@angular/compiler-cli": "^20.3.0",
|
||||
"@capacitor/cli": "latest",
|
||||
"@ionic/angular-toolkit": "latest",
|
||||
"typescript": "~5.9.2"
|
||||
}
|
||||
}
|
||||
|
After Width: | Height: | Size: 95 KiB |
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" standalone="no"?>
|
||||
<svg viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill="#F2F4F8" d="M45.1,-79.7C57.7,-70.9,66.4,-57.2,69.5,-43.1C72.6,-29,70,-14.5,71.7,1C73.5,16.5,79.6,33,75.1,44.6C70.6,56.2,55.4,63,41.1,70.5C26.9,78.1,13.4,86.3,-0.2,86.6C-13.7,86.9,-27.5,79.2,-40.1,70.7C-52.7,62.2,-64.3,53,-69.6,41.1C-74.9,29.2,-74.1,14.6,-72.7,0.8C-71.3,-13,-69.4,-26,-62.8,-35.7C-56.2,-45.5,-45,-52.1,-33.8,-61.6C-22.6,-71.1,-11.3,-83.5,2.5,-87.9C16.3,-92.2,32.6,-88.4,45.1,-79.7Z" transform="translate(100 100)" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 555 B |
|
Before Width: | Height: | Size: 15 KiB |
@@ -2,11 +2,15 @@ import { ApplicationConfig, provideBrowserGlobalErrorListeners, provideZoneChang
|
||||
import {provideRouter} from '@angular/router';
|
||||
|
||||
import {routes} from './app.routes';
|
||||
import {provideIonicAngular} from '@ionic/angular/standalone';
|
||||
import {provideHttpClient, withInterceptors} from "@angular/common/http";
|
||||
import {authInterceptor} from "./interceptors/auth-interceptor";
|
||||
|
||||
export const appConfig: ApplicationConfig = {
|
||||
providers: [
|
||||
provideBrowserGlobalErrorListeners(),
|
||||
provideZoneChangeDetection({eventCoalescing: true}),
|
||||
provideRouter(routes)
|
||||
provideRouter(routes), provideIonicAngular({}),
|
||||
provideHttpClient(withInterceptors([authInterceptor]))
|
||||
]
|
||||
};
|
||||
|
||||
@@ -1,342 +1,3 @@
|
||||
<!-- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -->
|
||||
<!-- * * * * * * * * * * * The content below * * * * * * * * * * * -->
|
||||
<!-- * * * * * * * * * * is only a placeholder * * * * * * * * * * -->
|
||||
<!-- * * * * * * * * * * and can be replaced. * * * * * * * * * * -->
|
||||
<!-- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -->
|
||||
<!-- * * * * * * * * * Delete the template below * * * * * * * * * -->
|
||||
<!-- * * * * * * * to get started with your project! * * * * * * * -->
|
||||
<!-- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -->
|
||||
|
||||
<style>
|
||||
:host {
|
||||
--bright-blue: oklch(51.01% 0.274 263.83);
|
||||
--electric-violet: oklch(53.18% 0.28 296.97);
|
||||
--french-violet: oklch(47.66% 0.246 305.88);
|
||||
--vivid-pink: oklch(69.02% 0.277 332.77);
|
||||
--hot-red: oklch(61.42% 0.238 15.34);
|
||||
--orange-red: oklch(63.32% 0.24 31.68);
|
||||
|
||||
--gray-900: oklch(19.37% 0.006 300.98);
|
||||
--gray-700: oklch(36.98% 0.014 302.71);
|
||||
--gray-400: oklch(70.9% 0.015 304.04);
|
||||
|
||||
--red-to-pink-to-purple-vertical-gradient: linear-gradient(
|
||||
180deg,
|
||||
var(--orange-red) 0%,
|
||||
var(--vivid-pink) 50%,
|
||||
var(--electric-violet) 100%
|
||||
);
|
||||
|
||||
--red-to-pink-to-purple-horizontal-gradient: linear-gradient(
|
||||
90deg,
|
||||
var(--orange-red) 0%,
|
||||
var(--vivid-pink) 50%,
|
||||
var(--electric-violet) 100%
|
||||
);
|
||||
|
||||
--pill-accent: var(--bright-blue);
|
||||
|
||||
font-family: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
|
||||
Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji",
|
||||
"Segoe UI Symbol";
|
||||
box-sizing: border-box;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 3.125rem;
|
||||
color: var(--gray-900);
|
||||
font-weight: 500;
|
||||
line-height: 100%;
|
||||
letter-spacing: -0.125rem;
|
||||
margin: 0;
|
||||
font-family: "Inter Tight", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
|
||||
Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji",
|
||||
"Segoe UI Symbol";
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 0;
|
||||
color: var(--gray-700);
|
||||
}
|
||||
|
||||
main {
|
||||
width: 100%;
|
||||
min-height: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 1rem;
|
||||
box-sizing: inherit;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.angular-logo {
|
||||
max-width: 9.2rem;
|
||||
}
|
||||
|
||||
.content {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
width: 100%;
|
||||
max-width: 700px;
|
||||
margin-bottom: 3rem;
|
||||
}
|
||||
|
||||
.content h1 {
|
||||
margin-top: 1.75rem;
|
||||
}
|
||||
|
||||
.content p {
|
||||
margin-top: 1.5rem;
|
||||
}
|
||||
|
||||
.divider {
|
||||
width: 1px;
|
||||
background: var(--red-to-pink-to-purple-vertical-gradient);
|
||||
margin-inline: 0.5rem;
|
||||
}
|
||||
|
||||
.pill-group {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: start;
|
||||
flex-wrap: wrap;
|
||||
gap: 1.25rem;
|
||||
}
|
||||
|
||||
.pill {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
--pill-accent: var(--bright-blue);
|
||||
background: color-mix(in srgb, var(--pill-accent) 5%, transparent);
|
||||
color: var(--pill-accent);
|
||||
padding-inline: 0.75rem;
|
||||
padding-block: 0.375rem;
|
||||
border-radius: 2.75rem;
|
||||
border: 0;
|
||||
transition: background 0.3s ease;
|
||||
font-family: var(--inter-font);
|
||||
font-size: 0.875rem;
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
line-height: 1.4rem;
|
||||
letter-spacing: -0.00875rem;
|
||||
text-decoration: none;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.pill:hover {
|
||||
background: color-mix(in srgb, var(--pill-accent) 15%, transparent);
|
||||
}
|
||||
|
||||
.pill-group .pill:nth-child(6n + 1) {
|
||||
--pill-accent: var(--bright-blue);
|
||||
}
|
||||
.pill-group .pill:nth-child(6n + 2) {
|
||||
--pill-accent: var(--electric-violet);
|
||||
}
|
||||
.pill-group .pill:nth-child(6n + 3) {
|
||||
--pill-accent: var(--french-violet);
|
||||
}
|
||||
|
||||
.pill-group .pill:nth-child(6n + 4),
|
||||
.pill-group .pill:nth-child(6n + 5),
|
||||
.pill-group .pill:nth-child(6n + 6) {
|
||||
--pill-accent: var(--hot-red);
|
||||
}
|
||||
|
||||
.pill-group svg {
|
||||
margin-inline-start: 0.25rem;
|
||||
}
|
||||
|
||||
.social-links {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.73rem;
|
||||
margin-top: 1.5rem;
|
||||
}
|
||||
|
||||
.social-links path {
|
||||
transition: fill 0.3s ease;
|
||||
fill: var(--gray-400);
|
||||
}
|
||||
|
||||
.social-links a:hover svg path {
|
||||
fill: var(--gray-900);
|
||||
}
|
||||
|
||||
@media screen and (max-width: 650px) {
|
||||
.content {
|
||||
flex-direction: column;
|
||||
width: max-content;
|
||||
}
|
||||
|
||||
.divider {
|
||||
height: 1px;
|
||||
width: 100%;
|
||||
background: var(--red-to-pink-to-purple-horizontal-gradient);
|
||||
margin-block: 1.5rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<main class="main">
|
||||
<div class="content">
|
||||
<div class="left-side">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 982 239"
|
||||
fill="none"
|
||||
class="angular-logo"
|
||||
>
|
||||
<g clip-path="url(#a)">
|
||||
<path
|
||||
fill="url(#b)"
|
||||
d="M388.676 191.625h30.849L363.31 31.828h-35.758l-56.215 159.797h30.848l13.174-39.356h60.061l13.256 39.356Zm-65.461-62.675 21.602-64.311h1.227l21.602 64.311h-44.431Zm126.831-7.527v70.202h-28.23V71.839h27.002v20.374h1.392c2.782-6.71 7.2-12.028 13.255-15.956 6.056-3.927 13.584-5.89 22.503-5.89 8.264 0 15.465 1.8 21.684 5.318 6.137 3.518 10.964 8.673 14.319 15.382 3.437 6.71 5.074 14.81 4.992 24.383v76.175h-28.23v-71.92c0-8.019-2.046-14.237-6.219-18.819-4.173-4.5-9.819-6.791-17.102-6.791-4.91 0-9.328 1.063-13.174 3.272-3.846 2.128-6.792 5.237-9.001 9.328-2.046 4.009-3.191 8.918-3.191 14.728ZM589.233 239c-10.147 0-18.82-1.391-26.103-4.091-7.282-2.7-13.092-6.382-17.511-10.964-4.418-4.582-7.528-9.655-9.164-15.219l25.448-6.136c1.145 2.372 2.782 4.663 4.991 6.954 2.209 2.291 5.155 4.255 8.837 5.81 3.683 1.554 8.428 2.291 14.074 2.291 8.019 0 14.647-1.964 19.884-5.81 5.237-3.845 7.856-10.227 7.856-19.064v-22.665h-1.391c-1.473 2.946-3.601 5.892-6.383 9.001-2.782 3.109-6.464 5.645-10.965 7.691-4.582 2.046-10.228 3.109-17.101 3.109-9.165 0-17.511-2.209-25.039-6.545-7.446-4.337-13.42-10.883-17.757-19.474-4.418-8.673-6.628-19.473-6.628-32.565 0-13.091 2.21-24.301 6.628-33.383 4.419-9.082 10.311-15.955 17.839-20.7 7.528-4.746 15.874-7.037 25.039-7.037 7.037 0 12.846 1.145 17.347 3.518 4.582 2.373 8.182 5.236 10.883 8.51 2.7 3.272 4.746 6.382 6.137 9.327h1.554v-19.8h27.821v121.749c0 10.228-2.454 18.737-7.364 25.447-4.91 6.709-11.538 11.7-20.048 15.055-8.509 3.355-18.165 4.991-28.884 4.991Zm.245-71.266c5.974 0 11.047-1.473 15.302-4.337 4.173-2.945 7.446-7.118 9.573-12.519 2.21-5.482 3.274-12.027 3.274-19.637 0-7.609-1.064-14.155-3.274-19.8-2.127-5.646-5.318-10.064-9.491-13.255-4.174-3.11-9.329-4.746-15.384-4.746s-11.537 1.636-15.792 4.91c-4.173 3.272-7.365 7.772-9.492 13.418-2.128 5.727-3.191 12.191-3.191 19.392 0 7.2 1.063 13.745 3.273 19.228 2.127 5.482 5.318 9.736 9.573 12.764 4.174 3.027 9.41 4.582 15.629 4.582Zm141.56-26.51V71.839h28.23v119.786h-27.412v-21.273h-1.227c-2.7 6.709-7.119 12.191-13.338 16.446-6.137 4.255-13.747 6.382-22.748 6.382-7.855 0-14.81-1.718-20.783-5.237-5.974-3.518-10.72-8.591-14.075-15.382-3.355-6.709-5.073-14.891-5.073-24.464V71.839h28.312v71.921c0 7.609 2.046 13.664 6.219 18.083 4.173 4.5 9.655 6.709 16.365 6.709 4.173 0 8.183-.982 12.111-3.028 3.927-2.045 7.118-5.072 9.655-9.082 2.537-4.091 3.764-9.164 3.764-15.218Zm65.707-109.395v159.796h-28.23V31.828h28.23Zm44.841 162.169c-7.61 0-14.402-1.391-20.457-4.091-6.055-2.7-10.883-6.791-14.32-12.109-3.518-5.319-5.237-11.946-5.237-19.801 0-6.791 1.228-12.355 3.765-16.773 2.536-4.419 5.891-7.937 10.228-10.637 4.337-2.618 9.164-4.664 14.647-6.055 5.4-1.391 11.046-2.373 16.856-3.027 7.037-.737 12.683-1.391 17.102-1.964 4.337-.573 7.528-1.555 9.574-2.782 1.963-1.309 3.027-3.273 3.027-5.973v-.491c0-5.891-1.718-10.391-5.237-13.664-3.518-3.191-8.51-4.828-15.056-4.828-6.955 0-12.356 1.473-16.447 4.5-4.009 3.028-6.71 6.546-8.183 10.719l-26.348-3.764c2.046-7.282 5.483-13.336 10.31-18.328 4.746-4.909 10.638-8.59 17.511-11.045 6.955-2.455 14.565-3.682 22.912-3.682 5.809 0 11.537.654 17.265 2.045s10.965 3.6 15.711 6.71c4.746 3.109 8.51 7.282 11.455 12.6 2.864 5.318 4.337 11.946 4.337 19.883v80.184h-27.166v-16.446h-.9c-1.719 3.355-4.092 6.464-7.201 9.328-3.109 2.864-6.955 5.237-11.619 6.955-4.828 1.718-10.229 2.536-16.529 2.536Zm7.364-20.701c5.646 0 10.556-1.145 14.729-3.354 4.173-2.291 7.364-5.237 9.655-9.001 2.292-3.763 3.355-7.854 3.355-12.273v-14.155c-.9.737-2.373 1.391-4.5 2.046-2.128.654-4.419 1.145-7.037 1.636-2.619.491-5.155.9-7.692 1.227-2.537.328-4.746.655-6.628.901-4.173.572-8.019 1.472-11.292 2.781-3.355 1.31-5.973 3.11-7.855 5.401-1.964 2.291-2.864 5.318-2.864 8.918 0 5.237 1.882 9.164 5.728 11.782 3.682 2.782 8.51 4.091 14.401 4.091Zm64.643 18.328V71.839h27.412v19.965h1.227c2.21-6.955 5.974-12.274 11.292-16.038 5.319-3.763 11.456-5.645 18.329-5.645 1.555 0 3.355.082 5.237.163 1.964.164 3.601.328 4.91.573v25.938c-1.227-.41-3.109-.819-5.646-1.146a58.814 58.814 0 0 0-7.446-.49c-5.155 0-9.738 1.145-13.829 3.354-4.091 2.209-7.282 5.236-9.655 9.164-2.373 3.927-3.519 8.427-3.519 13.5v70.448h-28.312ZM222.077 39.192l-8.019 125.923L137.387 0l84.69 39.192Zm-53.105 162.825-57.933 33.056-57.934-33.056 11.783-28.556h92.301l11.783 28.556ZM111.039 62.675l30.357 73.803H80.681l30.358-73.803ZM7.937 165.115 0 39.192 84.69 0 7.937 165.115Z"
|
||||
/>
|
||||
<path
|
||||
fill="url(#c)"
|
||||
d="M388.676 191.625h30.849L363.31 31.828h-35.758l-56.215 159.797h30.848l13.174-39.356h60.061l13.256 39.356Zm-65.461-62.675 21.602-64.311h1.227l21.602 64.311h-44.431Zm126.831-7.527v70.202h-28.23V71.839h27.002v20.374h1.392c2.782-6.71 7.2-12.028 13.255-15.956 6.056-3.927 13.584-5.89 22.503-5.89 8.264 0 15.465 1.8 21.684 5.318 6.137 3.518 10.964 8.673 14.319 15.382 3.437 6.71 5.074 14.81 4.992 24.383v76.175h-28.23v-71.92c0-8.019-2.046-14.237-6.219-18.819-4.173-4.5-9.819-6.791-17.102-6.791-4.91 0-9.328 1.063-13.174 3.272-3.846 2.128-6.792 5.237-9.001 9.328-2.046 4.009-3.191 8.918-3.191 14.728ZM589.233 239c-10.147 0-18.82-1.391-26.103-4.091-7.282-2.7-13.092-6.382-17.511-10.964-4.418-4.582-7.528-9.655-9.164-15.219l25.448-6.136c1.145 2.372 2.782 4.663 4.991 6.954 2.209 2.291 5.155 4.255 8.837 5.81 3.683 1.554 8.428 2.291 14.074 2.291 8.019 0 14.647-1.964 19.884-5.81 5.237-3.845 7.856-10.227 7.856-19.064v-22.665h-1.391c-1.473 2.946-3.601 5.892-6.383 9.001-2.782 3.109-6.464 5.645-10.965 7.691-4.582 2.046-10.228 3.109-17.101 3.109-9.165 0-17.511-2.209-25.039-6.545-7.446-4.337-13.42-10.883-17.757-19.474-4.418-8.673-6.628-19.473-6.628-32.565 0-13.091 2.21-24.301 6.628-33.383 4.419-9.082 10.311-15.955 17.839-20.7 7.528-4.746 15.874-7.037 25.039-7.037 7.037 0 12.846 1.145 17.347 3.518 4.582 2.373 8.182 5.236 10.883 8.51 2.7 3.272 4.746 6.382 6.137 9.327h1.554v-19.8h27.821v121.749c0 10.228-2.454 18.737-7.364 25.447-4.91 6.709-11.538 11.7-20.048 15.055-8.509 3.355-18.165 4.991-28.884 4.991Zm.245-71.266c5.974 0 11.047-1.473 15.302-4.337 4.173-2.945 7.446-7.118 9.573-12.519 2.21-5.482 3.274-12.027 3.274-19.637 0-7.609-1.064-14.155-3.274-19.8-2.127-5.646-5.318-10.064-9.491-13.255-4.174-3.11-9.329-4.746-15.384-4.746s-11.537 1.636-15.792 4.91c-4.173 3.272-7.365 7.772-9.492 13.418-2.128 5.727-3.191 12.191-3.191 19.392 0 7.2 1.063 13.745 3.273 19.228 2.127 5.482 5.318 9.736 9.573 12.764 4.174 3.027 9.41 4.582 15.629 4.582Zm141.56-26.51V71.839h28.23v119.786h-27.412v-21.273h-1.227c-2.7 6.709-7.119 12.191-13.338 16.446-6.137 4.255-13.747 6.382-22.748 6.382-7.855 0-14.81-1.718-20.783-5.237-5.974-3.518-10.72-8.591-14.075-15.382-3.355-6.709-5.073-14.891-5.073-24.464V71.839h28.312v71.921c0 7.609 2.046 13.664 6.219 18.083 4.173 4.5 9.655 6.709 16.365 6.709 4.173 0 8.183-.982 12.111-3.028 3.927-2.045 7.118-5.072 9.655-9.082 2.537-4.091 3.764-9.164 3.764-15.218Zm65.707-109.395v159.796h-28.23V31.828h28.23Zm44.841 162.169c-7.61 0-14.402-1.391-20.457-4.091-6.055-2.7-10.883-6.791-14.32-12.109-3.518-5.319-5.237-11.946-5.237-19.801 0-6.791 1.228-12.355 3.765-16.773 2.536-4.419 5.891-7.937 10.228-10.637 4.337-2.618 9.164-4.664 14.647-6.055 5.4-1.391 11.046-2.373 16.856-3.027 7.037-.737 12.683-1.391 17.102-1.964 4.337-.573 7.528-1.555 9.574-2.782 1.963-1.309 3.027-3.273 3.027-5.973v-.491c0-5.891-1.718-10.391-5.237-13.664-3.518-3.191-8.51-4.828-15.056-4.828-6.955 0-12.356 1.473-16.447 4.5-4.009 3.028-6.71 6.546-8.183 10.719l-26.348-3.764c2.046-7.282 5.483-13.336 10.31-18.328 4.746-4.909 10.638-8.59 17.511-11.045 6.955-2.455 14.565-3.682 22.912-3.682 5.809 0 11.537.654 17.265 2.045s10.965 3.6 15.711 6.71c4.746 3.109 8.51 7.282 11.455 12.6 2.864 5.318 4.337 11.946 4.337 19.883v80.184h-27.166v-16.446h-.9c-1.719 3.355-4.092 6.464-7.201 9.328-3.109 2.864-6.955 5.237-11.619 6.955-4.828 1.718-10.229 2.536-16.529 2.536Zm7.364-20.701c5.646 0 10.556-1.145 14.729-3.354 4.173-2.291 7.364-5.237 9.655-9.001 2.292-3.763 3.355-7.854 3.355-12.273v-14.155c-.9.737-2.373 1.391-4.5 2.046-2.128.654-4.419 1.145-7.037 1.636-2.619.491-5.155.9-7.692 1.227-2.537.328-4.746.655-6.628.901-4.173.572-8.019 1.472-11.292 2.781-3.355 1.31-5.973 3.11-7.855 5.401-1.964 2.291-2.864 5.318-2.864 8.918 0 5.237 1.882 9.164 5.728 11.782 3.682 2.782 8.51 4.091 14.401 4.091Zm64.643 18.328V71.839h27.412v19.965h1.227c2.21-6.955 5.974-12.274 11.292-16.038 5.319-3.763 11.456-5.645 18.329-5.645 1.555 0 3.355.082 5.237.163 1.964.164 3.601.328 4.91.573v25.938c-1.227-.41-3.109-.819-5.646-1.146a58.814 58.814 0 0 0-7.446-.49c-5.155 0-9.738 1.145-13.829 3.354-4.091 2.209-7.282 5.236-9.655 9.164-2.373 3.927-3.519 8.427-3.519 13.5v70.448h-28.312ZM222.077 39.192l-8.019 125.923L137.387 0l84.69 39.192Zm-53.105 162.825-57.933 33.056-57.934-33.056 11.783-28.556h92.301l11.783 28.556ZM111.039 62.675l30.357 73.803H80.681l30.358-73.803ZM7.937 165.115 0 39.192 84.69 0 7.937 165.115Z"
|
||||
/>
|
||||
</g>
|
||||
<defs>
|
||||
<radialGradient
|
||||
id="c"
|
||||
cx="0"
|
||||
cy="0"
|
||||
r="1"
|
||||
gradientTransform="rotate(118.122 171.182 60.81) scale(205.794)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop stop-color="#FF41F8" />
|
||||
<stop offset=".707" stop-color="#FF41F8" stop-opacity=".5" />
|
||||
<stop offset="1" stop-color="#FF41F8" stop-opacity="0" />
|
||||
</radialGradient>
|
||||
<linearGradient
|
||||
id="b"
|
||||
x1="0"
|
||||
x2="982"
|
||||
y1="192"
|
||||
y2="192"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop stop-color="#F0060B" />
|
||||
<stop offset="0" stop-color="#F0070C" />
|
||||
<stop offset=".526" stop-color="#CC26D5" />
|
||||
<stop offset="1" stop-color="#7702FF" />
|
||||
</linearGradient>
|
||||
<clipPath id="a"><path fill="#fff" d="M0 0h982v239H0z" /></clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
<h1>Hello, {{ title() }}</h1>
|
||||
<p>Congratulations! Your app is running. 🎉</p>
|
||||
</div>
|
||||
<div class="divider" role="separator" aria-label="Divider"></div>
|
||||
<div class="right-side">
|
||||
<div class="pill-group">
|
||||
@for (item of [
|
||||
{ title: 'Explore the Docs', link: 'https://angular.dev' },
|
||||
{ title: 'Learn with Tutorials', link: 'https://angular.dev/tutorials' },
|
||||
{ title: 'Prompt and best practices for AI', link: 'https://angular.dev/ai/develop-with-ai'},
|
||||
{ title: 'CLI Docs', link: 'https://angular.dev/tools/cli' },
|
||||
{ title: 'Angular Language Service', link: 'https://angular.dev/tools/language-service' },
|
||||
{ title: 'Angular DevTools', link: 'https://angular.dev/tools/devtools' },
|
||||
]; track item.title) {
|
||||
<a
|
||||
class="pill"
|
||||
[href]="item.link"
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
>
|
||||
<span>{{ item.title }}</span>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
height="14"
|
||||
viewBox="0 -960 960 960"
|
||||
width="14"
|
||||
fill="currentColor"
|
||||
>
|
||||
<path
|
||||
d="M200-120q-33 0-56.5-23.5T120-200v-560q0-33 23.5-56.5T200-840h280v80H200v560h560v-280h80v280q0 33-23.5 56.5T760-120H200Zm188-212-56-56 372-372H560v-80h280v280h-80v-144L388-332Z"
|
||||
/>
|
||||
</svg>
|
||||
</a>
|
||||
}
|
||||
</div>
|
||||
<div class="social-links">
|
||||
<a
|
||||
href="https://github.com/angular/angular"
|
||||
aria-label="Github"
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
>
|
||||
<svg
|
||||
width="25"
|
||||
height="24"
|
||||
viewBox="0 0 25 24"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
alt="Github"
|
||||
>
|
||||
<path
|
||||
d="M12.3047 0C5.50634 0 0 5.50942 0 12.3047C0 17.7423 3.52529 22.3535 8.41332 23.9787C9.02856 24.0946 9.25414 23.7142 9.25414 23.3871C9.25414 23.0949 9.24389 22.3207 9.23876 21.2953C5.81601 22.0377 5.09414 19.6444 5.09414 19.6444C4.53427 18.2243 3.72524 17.8449 3.72524 17.8449C2.61064 17.082 3.81137 17.0973 3.81137 17.0973C5.04697 17.1835 5.69604 18.3647 5.69604 18.3647C6.79321 20.2463 8.57636 19.7029 9.27978 19.3881C9.39052 18.5924 9.70736 18.0499 10.0591 17.7423C7.32641 17.4347 4.45429 16.3765 4.45429 11.6618C4.45429 10.3185 4.9311 9.22133 5.72065 8.36C5.58222 8.04931 5.16694 6.79833 5.82831 5.10337C5.82831 5.10337 6.85883 4.77319 9.2121 6.36459C10.1965 6.09082 11.2424 5.95546 12.2883 5.94931C13.3342 5.95546 14.3801 6.09082 15.3644 6.36459C17.7023 4.77319 18.7328 5.10337 18.7328 5.10337C19.3942 6.79833 18.9789 8.04931 18.8559 8.36C19.6403 9.22133 20.1171 10.3185 20.1171 11.6618C20.1171 16.3888 17.2409 17.4296 14.5031 17.7321C14.9338 18.1012 15.3337 18.8559 15.3337 20.0084C15.3337 21.6552 15.3183 22.978 15.3183 23.3779C15.3183 23.7009 15.5336 24.0854 16.1642 23.9623C21.0871 22.3484 24.6094 17.7341 24.6094 12.3047C24.6094 5.50942 19.0999 0 12.3047 0Z"
|
||||
/>
|
||||
</svg>
|
||||
</a>
|
||||
<a
|
||||
href="https://twitter.com/angular"
|
||||
aria-label="Twitter"
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
>
|
||||
<svg
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
alt="Twitter"
|
||||
>
|
||||
<path
|
||||
d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z"
|
||||
/>
|
||||
</svg>
|
||||
</a>
|
||||
<a
|
||||
href="https://www.youtube.com/channel/UCbn1OgGei-DV7aSRo_HaAiw"
|
||||
aria-label="Youtube"
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
>
|
||||
<svg
|
||||
width="29"
|
||||
height="20"
|
||||
viewBox="0 0 29 20"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
alt="Youtube"
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M27.4896 1.52422C27.9301 1.96749 28.2463 2.51866 28.4068 3.12258C29.0004 5.35161 29.0004 10 29.0004 10C29.0004 10 29.0004 14.6484 28.4068 16.8774C28.2463 17.4813 27.9301 18.0325 27.4896 18.4758C27.0492 18.9191 26.5 19.2389 25.8972 19.4032C23.6778 20 14.8068 20 14.8068 20C14.8068 20 5.93586 20 3.71651 19.4032C3.11363 19.2389 2.56449 18.9191 2.12405 18.4758C1.68361 18.0325 1.36732 17.4813 1.20683 16.8774C0.613281 14.6484 0.613281 10 0.613281 10C0.613281 10 0.613281 5.35161 1.20683 3.12258C1.36732 2.51866 1.68361 1.96749 2.12405 1.52422C2.56449 1.08095 3.11363 0.76113 3.71651 0.596774C5.93586 0 14.8068 0 14.8068 0C14.8068 0 23.6778 0 25.8972 0.596774C26.5 0.76113 27.0492 1.08095 27.4896 1.52422ZM19.3229 10L11.9036 5.77905V14.221L19.3229 10Z"
|
||||
/>
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<!-- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -->
|
||||
<!-- * * * * * * * * * * * The content above * * * * * * * * * * * * -->
|
||||
<!-- * * * * * * * * * * is only a placeholder * * * * * * * * * * * -->
|
||||
<!-- * * * * * * * * * * and can be replaced. * * * * * * * * * * * -->
|
||||
<!-- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -->
|
||||
<!-- * * * * * * * * * * End of Placeholder * * * * * * * * * * * * -->
|
||||
<!-- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -->
|
||||
|
||||
|
||||
<router-outlet />
|
||||
<ion-app>
|
||||
<ion-router-outlet></ion-router-outlet>
|
||||
</ion-app>
|
||||
@@ -1,3 +1,29 @@
|
||||
import {Routes} from '@angular/router';
|
||||
|
||||
export const routes: Routes = [];
|
||||
// TODO: Guard pour empêcher la recherche de pages
|
||||
export const routes: Routes = [
|
||||
{path: '', redirectTo: '/login', pathMatch: 'full'},
|
||||
{path: 'login', loadComponent: () => import('./pages/login/login.component').then(m => m.LoginComponent)},
|
||||
{
|
||||
path: '',
|
||||
loadComponent: () => import('./components/navbar/navbar.component').then(m => m.NavbarComponent),
|
||||
children: [
|
||||
{
|
||||
path: 'home',
|
||||
loadComponent: () => import('./pages/home/home.component').then(m => m.HomeComponent)
|
||||
},
|
||||
{
|
||||
path: 'groups',
|
||||
loadComponent: () => import('./pages/publication/publication.component').then(m => m.PublicationComponent)
|
||||
},
|
||||
{
|
||||
path: 'ranking',
|
||||
loadComponent: () => import('./pages/ranking/ranking.component').then(m => m.RankingComponent)
|
||||
},
|
||||
{
|
||||
path: 'social',
|
||||
loadComponent: () => import('./pages/social/social.component').then(m => m.SocialComponent)
|
||||
},
|
||||
]
|
||||
}
|
||||
];
|
||||
@@ -1,12 +1,11 @@
|
||||
import { Component, signal } from '@angular/core';
|
||||
import { RouterOutlet } from '@angular/router';
|
||||
import {Component} from '@angular/core';
|
||||
import {IonicModule} from "@ionic/angular";
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
imports: [RouterOutlet],
|
||||
imports: [IonicModule],
|
||||
templateUrl: './app.html',
|
||||
styleUrl: './app.css'
|
||||
})
|
||||
export class App {
|
||||
protected readonly title = signal('BeReadyFrontend');
|
||||
}
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
<div class="bg-white m-4 rounded-2xl border border-amber-200 shadow-sm p-4 space-y-3">
|
||||
|
||||
<div class="grid grid-cols-5 items-center">
|
||||
|
||||
<h3 class="col-span-4 text-base font-semibold text-gray-900 m-0">
|
||||
{{ challenge().label }}
|
||||
</h3>
|
||||
</div>
|
||||
|
||||
<p class="text-[11px] text-gray-500 leading-relaxed">{{ challenge().libelle }}</p>
|
||||
|
||||
<div class="grid grid-cols-5 items-center">
|
||||
<span class="col-span-4 text-[11px] text-gray-500">
|
||||
Aucun malus pour ce défi
|
||||
</span>
|
||||
|
||||
<div class="col-span-1 flex justify-end">
|
||||
<ion-button
|
||||
fill="clear"
|
||||
class="m-0 p-0 min-h-0 text-[11px] font-black bg-black text-white rounded-3xl"
|
||||
style="--padding-top: 4px; --padding-bottom: 4px;"
|
||||
(click)="setOpen(true)">
|
||||
Relever
|
||||
</ion-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ion-modal [isOpen]="isModalOpen">
|
||||
<ng-template>
|
||||
<ion-header>
|
||||
<ion-toolbar>
|
||||
<ion-title>Défi Quotidien</ion-title>
|
||||
<ion-buttons slot="start" style="--ion-color-primary: #0054E9;">
|
||||
<ion-back-button default-href="" (click)="setOpen(false)"></ion-back-button>
|
||||
</ion-buttons>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
<ion-content class="ion-padding m-1" style="--background: #f7f6f2;">
|
||||
|
||||
<div class="mt-4 bg-white rounded-2xl shadow-sm p-4 space-y-3">
|
||||
<div class="grid grid-cols-5 items-center">
|
||||
<h3 class="col-span-4 text-base font-semibold text-gray-900 m-0">
|
||||
{{ challenge().label }}
|
||||
</h3>
|
||||
</div>
|
||||
|
||||
<p class="text-[11px] text-gray-500 leading-relaxed">{{ challenge().libelle }}</p>
|
||||
</div>
|
||||
|
||||
<app-tooltip title="Aucun malus si non réalisé"
|
||||
content="entièrement facultatif et solo. Points réduits comparé à un défi classique."></app-tooltip>
|
||||
|
||||
<div class="mb-6">
|
||||
<app-proof-form #proofForm></app-proof-form>
|
||||
</div>
|
||||
|
||||
<ion-button expand="block" (click)="sendProof(challenge().id)">Soumettre ma preuve</ion-button>
|
||||
|
||||
</ion-content>
|
||||
</ng-template>
|
||||
</ion-modal>
|
||||
@@ -0,0 +1,78 @@
|
||||
import {Component, inject, input, viewChild} from '@angular/core';
|
||||
import {IonicModule, LoadingController, ToastController} from "@ionic/angular";
|
||||
import {GetRandomChallengeDto, RandomchallengesService} from "../../services/api";
|
||||
import {firstValueFrom} from "rxjs";
|
||||
import {TooltipComponent} from "../tooltip/tooltip.component";
|
||||
import {ProofFormComponent} from "../proof-form/proof-form.component";
|
||||
import {addIcons} from "ionicons";
|
||||
import {checkmarkCircleOutline} from "ionicons/icons";
|
||||
|
||||
addIcons({
|
||||
"checkmark-circle": checkmarkCircleOutline,
|
||||
})
|
||||
|
||||
@Component({
|
||||
selector: 'app-challenge-card',
|
||||
templateUrl: './challenge-card.component.html',
|
||||
styleUrls: ['./challenge-card.component.scss'],
|
||||
imports: [
|
||||
IonicModule,
|
||||
TooltipComponent,
|
||||
ProofFormComponent
|
||||
]
|
||||
})
|
||||
export class ChallengeCardComponent {
|
||||
private randomChallengesService = inject(RandomchallengesService);
|
||||
private toastCtrl = inject(ToastController);
|
||||
private loadCtrl = inject(LoadingController);
|
||||
|
||||
challenge = input.required<GetRandomChallengeDto>();
|
||||
proof = viewChild<ProofFormComponent>('proofForm');
|
||||
|
||||
isModalOpen = false;
|
||||
|
||||
async setOpen(isOpen: boolean) {
|
||||
this.isModalOpen = isOpen;
|
||||
}
|
||||
|
||||
async sendProof(randomChallengeId: number) {
|
||||
const file = this.proof().proofForm.value.proof;
|
||||
|
||||
if (!file) {
|
||||
const toast = await this.toastCtrl.create({
|
||||
message: 'Aucune preuve n\'a été déposée',
|
||||
duration: 2000,
|
||||
color: 'danger'
|
||||
});
|
||||
await toast.present();
|
||||
return;
|
||||
}
|
||||
|
||||
const loading = await this.loadCtrl.create({
|
||||
message: 'Chargement...',
|
||||
spinner: 'lines-sharp-small'
|
||||
});
|
||||
await loading.present();
|
||||
|
||||
try {
|
||||
await firstValueFrom(this.randomChallengesService.patchProofEndpoint(randomChallengeId, file));
|
||||
|
||||
this.isModalOpen = false;
|
||||
const toast = await this.toastCtrl.create({
|
||||
message: 'La preuve de ta réussite a bien été déposée',
|
||||
duration: 2000,
|
||||
color: 'success'
|
||||
});
|
||||
await toast.present();
|
||||
} catch (e) {
|
||||
this.isModalOpen = false;
|
||||
const toast = await this.toastCtrl.create({
|
||||
message: e.error ?? "Impossible de déposer une preuve",
|
||||
duration: 2000,
|
||||
color: 'danger'
|
||||
});
|
||||
await toast.present();
|
||||
}
|
||||
await loading.dismiss();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<div class="rounded-lg m-3 bg-white border border-gray-200 items-center h-full max-h-48 overflow-scroll">
|
||||
@if (userChallenges().length > 0) {
|
||||
@for (challenge of userChallenges(); track challenge.challengeTitle) {
|
||||
<ion-item lines="none" class="border border-gray-300 rounded-xl m-2">
|
||||
<div class="grid grid-cols-[1fr_auto] gap-2 items-start w-full px-3 py-2">
|
||||
<div>
|
||||
<p class="m-0 text-sm text-gray-500">{{ challenge.challengeTitle }}</p>
|
||||
<p class="m-0 mt-1 text-xs text-gray-500">{{ challenge.challengeDescription }}</p>
|
||||
</div>
|
||||
<div class="text-right shrink-0">
|
||||
<p class="m-0 mt-1 text-xs text-gray-400">{{ challenge.challengeStartDate }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</ion-item>
|
||||
}
|
||||
} @else {
|
||||
<ion-item lines="none" class="border border-stone-200 rounded-xl m-3" style="--background: #fafaf8;">
|
||||
<div class="flex flex-col items-center w-full px-5 py-8 gap-3">
|
||||
<div class="w-10 h-10 rounded-full bg-stone-100 border border-stone-200 flex items-center justify-center">
|
||||
<ion-icon name="trophy" style="color:#a8a090; font-size:20px;"></ion-icon>
|
||||
</div>
|
||||
<div class="text-center">
|
||||
<p class="m-0 text-sm font-medium text-stone-400">Aucun défi réalisé</p>
|
||||
<p class="m-0 mt-1 text-xs text-stone-300 leading-relaxed">Vos premiers défis apparaîtront ici</p>
|
||||
</div>
|
||||
</div>
|
||||
</ion-item>
|
||||
}
|
||||
</div>
|
||||
@@ -0,0 +1,15 @@
|
||||
import {Component, input} from '@angular/core';
|
||||
import {IonicModule} from "@ionic/angular";
|
||||
import {GetUserChallengeDto} from "../../services/api";
|
||||
|
||||
@Component({
|
||||
selector: 'app-challenges-accomplished',
|
||||
templateUrl: './challenges-accomplished.component.html',
|
||||
styleUrls: ['./challenges-accomplished.component.scss'],
|
||||
imports: [
|
||||
IonicModule
|
||||
]
|
||||
})
|
||||
export class ChallengesAccomplishedComponent {
|
||||
userChallenges = input.required<GetUserChallengeDto[]>();
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
<div class="bg-white rounded-xl p-5 shadow-sm border border-gray-200">
|
||||
<form [formGroup]="designationForm" class="space-y-5">
|
||||
<div class="space-y-3 max-h-[70vh] overflow-y-auto">
|
||||
<ion-label class="text-sm text-gray-500 block">
|
||||
Choisis ton titre de préstige
|
||||
</ion-label>
|
||||
|
||||
<ion-radio-group formControlName="designationId">
|
||||
@for (designation of designations(); track designation.id) {
|
||||
<ion-item lines="none" class="rounded-lg border border-gray-100">
|
||||
<ion-radio [value]="designation.id" class="text-sm text-gray-700">{{ designation.label }}
|
||||
</ion-radio>
|
||||
</ion-item>
|
||||
}
|
||||
</ion-radio-group>
|
||||
</div>
|
||||
|
||||
<ion-button expand="block"
|
||||
class="mt-6 rounded-xl font-medium"
|
||||
style="--background: #1f2937;"
|
||||
(click)="updateDesignation()">
|
||||
Modifier
|
||||
</ion-button>
|
||||
</form>
|
||||
</div>
|
||||
@@ -0,0 +1,101 @@
|
||||
import {Component, inject, input, OnInit, output, signal} from '@angular/core';
|
||||
import {FormControl, FormGroup, ReactiveFormsModule} from "@angular/forms";
|
||||
import {IonicModule, LoadingController, ToastController} from "@ionic/angular";
|
||||
import {DesignationsService, GetDesignationDto, GetUserDetailsDto, UsersService} from "../../services/api";
|
||||
import {firstValueFrom} from "rxjs";
|
||||
|
||||
@Component({
|
||||
selector: 'app-designation-form',
|
||||
templateUrl: './designation-form.component.html',
|
||||
styleUrls: ['./designation-form.component.scss'],
|
||||
imports: [
|
||||
IonicModule,
|
||||
ReactiveFormsModule
|
||||
]
|
||||
})
|
||||
export class DesignationFormComponent implements OnInit {
|
||||
private designationsService = inject(DesignationsService);
|
||||
private usersService = inject(UsersService);
|
||||
private loadCtrl = inject(LoadingController);
|
||||
private toastCtrl = inject(ToastController);
|
||||
|
||||
designationForm: FormGroup = new FormGroup({
|
||||
designationId: new FormControl<string>(null)
|
||||
});
|
||||
|
||||
designations = signal<GetDesignationDto[]>([]);
|
||||
user = input.required<GetUserDetailsDto>();
|
||||
userDesignation = output<GetUserDetailsDto>();
|
||||
|
||||
async ngOnInit() {
|
||||
const loading = await this.loadCtrl.create({
|
||||
message: 'Chargement...',
|
||||
spinner: 'lines-sharp-small'
|
||||
});
|
||||
await loading.present();
|
||||
|
||||
this.designationForm.patchValue({
|
||||
designationId: this.user().designationId,
|
||||
});
|
||||
|
||||
try {
|
||||
const designation = await firstValueFrom(this.designationsService.getAllDesignationsEndpoint());
|
||||
this.designations.set(designation);
|
||||
|
||||
await loading.dismiss();
|
||||
} catch {
|
||||
const toast = await this.toastCtrl.create({
|
||||
message: 'Impossible de récupérer les titres',
|
||||
duration: 2000,
|
||||
color: 'danger'
|
||||
});
|
||||
await toast.present();
|
||||
await loading.dismiss();
|
||||
}
|
||||
}
|
||||
|
||||
async updateDesignation() {
|
||||
const loading = await this.loadCtrl.create({
|
||||
message: 'Modification...',
|
||||
spinner: 'lines-sharp-small'
|
||||
});
|
||||
await loading.present();
|
||||
|
||||
try {
|
||||
const form = this.designationForm.getRawValue();
|
||||
const label = this.designations().find(x => x.id == form.designationId).label;
|
||||
|
||||
await firstValueFrom(this.usersService.patchUserDesignationEndpoint(form));
|
||||
const userEdited = {
|
||||
id: this.user().id,
|
||||
firstName: this.user().firstName,
|
||||
name: this.user().name,
|
||||
username: this.user().username,
|
||||
email: this.user().email,
|
||||
designationId: form.designationId,
|
||||
designationName: label,
|
||||
creationDate: this.user().creationDate,
|
||||
getUserStatsDto: this.user().getUserStatsDto
|
||||
}
|
||||
|
||||
this.userDesignation.emit(userEdited);
|
||||
|
||||
const toast = await this.toastCtrl.create({
|
||||
message: 'Modification réussie',
|
||||
duration: 2000,
|
||||
color: 'success'
|
||||
});
|
||||
|
||||
await loading.dismiss();
|
||||
await toast.present();
|
||||
} catch {
|
||||
const toast = await this.toastCtrl.create({
|
||||
message: 'Modification impossible',
|
||||
duration: 2000,
|
||||
color: 'danger'
|
||||
});
|
||||
await loading.dismiss();
|
||||
await toast.present();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
@if (friendsRequest().length) {
|
||||
<div class="rounded-xl px-5 m-3 bg-white overflow-auto font-mono border border-gray-300">
|
||||
<ion-list>
|
||||
@for (request of friendsRequest(); track request.userId; let i = $index) {
|
||||
@if (i == friendsRequest().length - 1) {
|
||||
<ion-item lines="none">
|
||||
<ion-avatar slot="start" class="w-5 h-5">
|
||||
<img alt="Silhouette of a person's head"
|
||||
src="https://ionicframework.com/docs/img/demos/avatar.svg"/>
|
||||
</ion-avatar>
|
||||
<ion-label class="text-xs font-mono">{{ request.username }}</ion-label>
|
||||
<ion-button fill="clear" (click)="acceptRequest(request)">
|
||||
<ion-icon slot="icon-only" name="check" class="text-green-600 m-0"></ion-icon>
|
||||
</ion-button>
|
||||
<app-pipe></app-pipe>
|
||||
<ion-button fill="clear" (click)="rejectRequest(request.userId)">
|
||||
<ion-icon slot="icon-only" name="close" class="text-red-600 m-0"></ion-icon>
|
||||
</ion-button>
|
||||
</ion-item>
|
||||
} @else {
|
||||
<ion-item lines="full">
|
||||
<ion-avatar slot="start" class="w-5 h-5">
|
||||
<img alt="Silhouette of a person's head"
|
||||
src="https://ionicframework.com/docs/img/demos/avatar.svg"/>
|
||||
</ion-avatar>
|
||||
<ion-label class="text-xs font-mono">{{ request.username }}</ion-label>
|
||||
<ion-button fill="clear" (click)="acceptRequest(request)">
|
||||
<ion-icon slot="icon-only" name="check" class="text-green-600 m-0"></ion-icon>
|
||||
</ion-button>
|
||||
<app-pipe></app-pipe>
|
||||
<ion-button fill="clear" (click)="rejectRequest(request.userId)">
|
||||
<ion-icon slot="icon-only" name="close" class="text-red-600 m-0"></ion-icon>
|
||||
</ion-button>
|
||||
</ion-item>
|
||||
}
|
||||
}
|
||||
</ion-list>
|
||||
</div>
|
||||
} @else {
|
||||
<ion-item lines="none" class="border border-stone-200 rounded-xl m-3" style="--background: #fafaf8;">
|
||||
<div class="flex flex-col items-center w-full px-10 py-20 gap-3">
|
||||
<div class="w-10 h-10 rounded-full bg-stone-100 border border-stone-200 flex items-center justify-center">
|
||||
<ion-icon name="people-outline" style="color:#a8a090; font-size:20px;"></ion-icon>
|
||||
</div>
|
||||
<div class="text-center">
|
||||
<p class="m-0 text-sm font-medium text-stone-400">Ajoutez vos amis</p>
|
||||
<p class="m-0 mt-1 text-xs text-stone-300 leading-relaxed">Vos demandes d'amis apparaîtront ici</p>
|
||||
</div>
|
||||
</div>
|
||||
</ion-item>
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
import {Component, inject} from '@angular/core';
|
||||
import {IonicModule, LoadingController, ToastController} from "@ionic/angular";
|
||||
import {checkmarkCircleOutline, closeCircleOutline, peopleOutline} from 'ionicons/icons';
|
||||
import {addIcons} from "ionicons";
|
||||
import {PipeComponent} from "../pipe/pipe.component";
|
||||
import {FriendsService, GetFriendRequestDto} from "../../services/api";
|
||||
import {firstValueFrom} from "rxjs";
|
||||
import {FriendsStateService} from "../../services/friends-state";
|
||||
|
||||
addIcons({
|
||||
'check': checkmarkCircleOutline,
|
||||
'close': closeCircleOutline,
|
||||
'people-outline': peopleOutline
|
||||
});
|
||||
|
||||
@Component({
|
||||
selector: 'app-friend-request',
|
||||
templateUrl: './friend-request.component.html',
|
||||
styleUrls: ['./friend-request.component.scss'],
|
||||
imports: [
|
||||
IonicModule,
|
||||
PipeComponent
|
||||
]
|
||||
})
|
||||
export class FriendRequestComponent {
|
||||
private friendsService = inject(FriendsService);
|
||||
private toastCtrl = inject(ToastController);
|
||||
private friendsState = inject(FriendsStateService);
|
||||
private loadCtrl = inject(LoadingController)
|
||||
|
||||
friendsRequest = this.friendsState.requests;
|
||||
|
||||
async acceptRequest(request: GetFriendRequestDto) {
|
||||
const loading = await this.loadCtrl.create({
|
||||
message: 'Chargement...',
|
||||
spinner: 'lines-sharp-small'
|
||||
});
|
||||
await loading.present();
|
||||
|
||||
try {
|
||||
await firstValueFrom(this.friendsService.acceptFriendRequestEndpoint(request.userId));
|
||||
this.friendsState.acceptRequest(request);
|
||||
const toast = await this.toastCtrl.create({
|
||||
message: 'Demande d\'ami acceptée',
|
||||
duration: 1000,
|
||||
color: 'success'
|
||||
});
|
||||
await toast.present();
|
||||
} catch (e) {
|
||||
const toast = await this.toastCtrl.create({
|
||||
message: 'Echec de l\'acceptation',
|
||||
duration: 1000,
|
||||
color: 'danger'
|
||||
});
|
||||
await toast.present();
|
||||
}
|
||||
await loading.dismiss();
|
||||
}
|
||||
|
||||
async rejectRequest(id: number) {
|
||||
const loading = await this.loadCtrl.create({
|
||||
message: 'Chargement...',
|
||||
spinner: 'lines-sharp-small'
|
||||
});
|
||||
await loading.present();
|
||||
|
||||
try {
|
||||
await firstValueFrom(this.friendsService.rejectFriendRequestEndpoint(id));
|
||||
this.friendsState.removeRequest(id);
|
||||
const toast = await this.toastCtrl.create({
|
||||
message: 'Demande d\'ami refusée',
|
||||
duration: 1000,
|
||||
color: 'success'
|
||||
});
|
||||
await toast.present();
|
||||
} catch (e) {
|
||||
const toast = await this.toastCtrl.create({
|
||||
message: 'Echec du refus',
|
||||
duration: 1000,
|
||||
color: 'danger'
|
||||
});
|
||||
await toast.present();
|
||||
}
|
||||
await loading.dismiss();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
@if (friends().length) {
|
||||
<div class="rounded-xl px-5 m-3 bg-white font-mono border border-gray-300">
|
||||
<ion-list>
|
||||
@for (friend of friends(); track friend.friendId; let i = $index) {
|
||||
@if (i == friends().length - 1) {
|
||||
<ion-item lines="none">
|
||||
<ion-avatar slot="start" class="w-5 h-5">
|
||||
<img alt="Silhouette of a person's head"
|
||||
src="https://ionicframework.com/docs/img/demos/avatar.svg"/>
|
||||
</ion-avatar>
|
||||
<ion-label class="text-xs font-mono font-bold"
|
||||
(click)="setOpen(true, friend.friendId)">{{ friend.username }}
|
||||
</ion-label>
|
||||
<ion-label class="text-xs font-mono text-gray-400">{{ friend.score }} <em>pts</em></ion-label>
|
||||
<ion-button fill="clear" (click)="deleteFriend(friend.friendId)">
|
||||
<ion-icon slot="icon-only" name="close" class="text-red-600"></ion-icon>
|
||||
</ion-button>
|
||||
</ion-item>
|
||||
} @else {
|
||||
<ion-item lines="full">
|
||||
<ion-avatar slot="start" class="w-5 h-5">
|
||||
<img alt="Silhouette of a person's head"
|
||||
src="https://ionicframework.com/docs/img/demos/avatar.svg"/>
|
||||
</ion-avatar>
|
||||
<ion-label class="text-xs font-mono font-bold"
|
||||
(click)="setOpen(true, friend.friendId)">{{ friend.username }}
|
||||
</ion-label>
|
||||
<ion-label class="text-xs font-mono text-gray-400">{{ friend.score }} <em>pts</em></ion-label>
|
||||
<ion-button fill="clear" (click)="deleteFriend(friend.friendId)">
|
||||
<ion-icon slot="icon-only" name="close" class="text-red-600"></ion-icon>
|
||||
</ion-button>
|
||||
</ion-item>
|
||||
}
|
||||
}
|
||||
</ion-list>
|
||||
</div>
|
||||
} @else {
|
||||
<ion-item lines="none" class="border border-stone-200 rounded-xl m-3" style="--background: #fafaf8;">
|
||||
<div class="flex flex-col items-center w-full px-10 py-20 gap-3">
|
||||
<div class="w-10 h-10 rounded-full bg-stone-100 border border-stone-200 flex items-center justify-center">
|
||||
<ion-icon name="people" style="color:#a8a090; font-size:20px;"></ion-icon>
|
||||
</div>
|
||||
<div class="text-center">
|
||||
<p class="m-0 text-sm font-medium text-stone-400">Ajoutez vos amis</p>
|
||||
<p class="m-0 mt-1 text-xs text-stone-300 leading-relaxed">Vos amis apparaîtront ici</p>
|
||||
</div>
|
||||
</div>
|
||||
</ion-item>
|
||||
}
|
||||
|
||||
<ion-modal [isOpen]="isModalOpen">
|
||||
<ng-template>
|
||||
<ion-header>
|
||||
<ion-toolbar>
|
||||
<ion-title>Profil</ion-title>
|
||||
<ion-buttons slot="start" style="--ion-color-primary: #0054E9;">
|
||||
<ion-back-button default-href="" (click)="setOpen(false, null)"></ion-back-button>
|
||||
</ion-buttons>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
<ion-content class="ion-padding" style="--background: #f7f6f2;">
|
||||
<app-generic-user-info [userInfo]="selectedFriend()"></app-generic-user-info>
|
||||
</ion-content>
|
||||
</ng-template>
|
||||
</ion-modal>
|
||||
@@ -0,0 +1,80 @@
|
||||
import {Component, inject, signal} from '@angular/core';
|
||||
import {IonicModule, LoadingController, ToastController} from "@ionic/angular";
|
||||
import {closeCircleOutline, peopleOutline} from 'ionicons/icons';
|
||||
import {addIcons} from "ionicons";
|
||||
import {FriendsService, GetUserDto, UsersService} from "../../services/api";
|
||||
import {firstValueFrom} from "rxjs";
|
||||
import {FriendsStateService} from "../../services/friends-state";
|
||||
import {GenericUserInfoComponent} from "../generic-user-info/generic-user-info.component";
|
||||
|
||||
addIcons({
|
||||
'close': closeCircleOutline,
|
||||
'people': peopleOutline
|
||||
});
|
||||
|
||||
@Component({
|
||||
selector: 'app-friends-list',
|
||||
templateUrl: './friends-list.component.html',
|
||||
styleUrls: ['./friends-list.component.scss'],
|
||||
imports: [
|
||||
IonicModule,
|
||||
GenericUserInfoComponent
|
||||
]
|
||||
})
|
||||
export class FriendsListComponent {
|
||||
private friendsService = inject(FriendsService);
|
||||
private usersService = inject(UsersService);
|
||||
private toastCtrl = inject(ToastController);
|
||||
private friendsState = inject(FriendsStateService);
|
||||
private loadCtrl = inject(LoadingController)
|
||||
|
||||
selectedFriend = signal<GetUserDto>(null);
|
||||
|
||||
isModalOpen = false;
|
||||
|
||||
friends = this.friendsState.friends;
|
||||
|
||||
async deleteFriend(friendId: number) {
|
||||
const loading = await this.loadCtrl.create({
|
||||
message: 'Chargement...',
|
||||
spinner: 'lines-sharp-small'
|
||||
});
|
||||
await loading.present();
|
||||
|
||||
try {
|
||||
await firstValueFrom(this.friendsService.deleteFriendEndpoint(friendId));
|
||||
const toast = await this.toastCtrl.create({
|
||||
message: 'Vous avez supprimé cet ami',
|
||||
duration: 2000,
|
||||
color: 'success'
|
||||
});
|
||||
await toast.present();
|
||||
} catch (e) {
|
||||
const toast = await this.toastCtrl.create({
|
||||
message: 'Vous ne pouvez pas supprimer cet ami',
|
||||
duration: 2000,
|
||||
color: 'danger'
|
||||
});
|
||||
await toast.present();
|
||||
}
|
||||
this.friendsState.removeFriend(friendId);
|
||||
await loading.dismiss();
|
||||
}
|
||||
|
||||
async setOpen(isOpen: boolean, userId: number) {
|
||||
if (isOpen) {
|
||||
try {
|
||||
const userInfo = await firstValueFrom(this.usersService.getUserEndpoint(userId));
|
||||
this.selectedFriend.set(userInfo);
|
||||
} catch (e) {
|
||||
const toast = await this.toastCtrl.create({
|
||||
message: 'Impossible de charger les données du joueur',
|
||||
duration: 2000,
|
||||
color: 'primary'
|
||||
});
|
||||
await toast.present();
|
||||
}
|
||||
}
|
||||
this.isModalOpen = isOpen;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
@if (proofs().length > 0) {
|
||||
@if (!modal) {
|
||||
<div class="bg-white rounded-lg p-2 shadow-sm border border-gray-200 overflow-scroll max-h-full">
|
||||
<div class="grid grid-cols-4 gap-3">
|
||||
@for (p of proofs(); track p) {
|
||||
<img [src]="'data:image/jpeg;base64,' + p.proof"
|
||||
class="w-20 h-20 object-cover"
|
||||
alt=""
|
||||
(click)="openProof(p.proof)"
|
||||
/>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
} @else {
|
||||
<div class="fixed inset-0 flex items-center justify-center z-50" (click)="closeProof()">
|
||||
<button class="absolute top-15 right-1 text-gray-300 text-4xl font-bold p-5 bg-transparent"
|
||||
(click)="closeProof()">
|
||||
<ion-icon name="close-circle-outline"></ion-icon>
|
||||
</button>
|
||||
|
||||
<img [src]="'data:image/jpeg;base64,' + selectedProof()"
|
||||
class="w-[90%] h-[90%] object-cover rounded-md mt-10"
|
||||
alt=""
|
||||
/>
|
||||
|
||||
</div>
|
||||
}
|
||||
} @else {
|
||||
<ion-item lines="none" class="border border-stone-200 rounded-xl m-3" style="--background: #fafaf8;">
|
||||
<div class="flex flex-col items-center w-full px-5 py-8 gap-3">
|
||||
<div class="w-10 h-10 rounded-full bg-stone-100 border border-stone-200 flex items-center justify-center">
|
||||
<ion-icon name="image" style="color:#a8a090; font-size:20px;"></ion-icon>
|
||||
</div>
|
||||
<div class="text-center">
|
||||
<p class="m-0 text-sm font-medium text-stone-400">C'est bien vide par ici...</p>
|
||||
<p class="m-0 mt-1 text-xs text-stone-300 leading-relaxed">Participe à des défis pour remplir ta galerie
|
||||
!</p>
|
||||
</div>
|
||||
</div>
|
||||
</ion-item>
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
import {Component, inject, OnInit, signal} from '@angular/core';
|
||||
import {IonicModule, LoadingController, ToastController} from "@ionic/angular";
|
||||
import {GetUserProofDto, UsersService} from "../../services/api";
|
||||
import {firstValueFrom} from "rxjs";
|
||||
import {addIcons} from "ionicons";
|
||||
import {closeCircleOutline, imageOutline} from "ionicons/icons";
|
||||
|
||||
addIcons({
|
||||
'close-circle-outline': closeCircleOutline,
|
||||
'image': imageOutline,
|
||||
})
|
||||
|
||||
@Component({
|
||||
selector: 'app-gallery',
|
||||
templateUrl: './gallery.component.html',
|
||||
styleUrls: ['./gallery.component.scss'],
|
||||
imports: [
|
||||
IonicModule
|
||||
]
|
||||
})
|
||||
export class GalleryComponent implements OnInit {
|
||||
private loadCtrl = inject(LoadingController);
|
||||
private usersService = inject(UsersService);
|
||||
private toastCtrl = inject(ToastController);
|
||||
|
||||
proofs = signal<GetUserProofDto[]>([]);
|
||||
selectedProof = signal<string>("");
|
||||
|
||||
modal = false;
|
||||
|
||||
async ngOnInit() {
|
||||
const loading = await this.loadCtrl.create({
|
||||
message: 'Chargement...',
|
||||
spinner: 'lines-sharp-small'
|
||||
});
|
||||
await loading.present();
|
||||
|
||||
try {
|
||||
const proofs = await firstValueFrom(this.usersService.getAllUserProofsEndpoint());
|
||||
this.proofs.set(proofs);
|
||||
|
||||
await loading.dismiss();
|
||||
} catch {
|
||||
const toast = await this.toastCtrl.create({
|
||||
message: 'Impossible de charger la galerie photos',
|
||||
duration: 2000,
|
||||
color: 'danger'
|
||||
});
|
||||
await loading.dismiss();
|
||||
await toast.present();
|
||||
}
|
||||
}
|
||||
|
||||
async openProof(proof: string) {
|
||||
const loading = await this.loadCtrl.create({
|
||||
message: 'Chargement...',
|
||||
spinner: 'lines-sharp-small'
|
||||
});
|
||||
await loading.present();
|
||||
|
||||
this.selectedProof.set(proof);
|
||||
this.modal = true;
|
||||
|
||||
await loading.dismiss();
|
||||
}
|
||||
|
||||
closeProof() {
|
||||
this.modal = false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
<div class="rounded-lg px-5 m-3 bg-white border border-gray-200 grid grid-cols-3 items-center">
|
||||
<div>
|
||||
<ion-avatar slot="start" class="w-20 h-20 p-2">
|
||||
<img alt=""
|
||||
src="https://ionicframework.com/docs/img/demos/avatar.svg"/>
|
||||
</ion-avatar>
|
||||
</div>
|
||||
<div class="col-span-2 py-3">
|
||||
<ion-label class="text-[15px] font-sans font-bold block">
|
||||
{{ userInfo()?.firstName }} {{ userInfo()?.name.charAt(0) }}.
|
||||
</ion-label>
|
||||
<ion-label class="text-xs font-mono block text-gray-400 mt-0.5">
|
||||
{{ userInfo()?.username }}
|
||||
</ion-label>
|
||||
<ion-label
|
||||
class="text-[10px] font-sans font-semibold block mt-2 bg-gray-100 text-gray-500 rounded-full px-2 py-0.5 w-fit">
|
||||
@if (userInfo().designationName) {
|
||||
⚡ {{ userInfo().designationName }}
|
||||
} @else {
|
||||
⚡ En sommeil
|
||||
}
|
||||
</ion-label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-2 px-1">
|
||||
<div class="rounded-lg px-4 py-0.5 m-2 bg-white border border-gray-200">
|
||||
<p class="text-2xl font-black font-mono mb-0.5">{{ userInfo().getUserStatsDto.totalChallenge }}</p>
|
||||
<p class="text-[11px] font-semibold font-mono text-gray-400 mt-0">Défis Réalisés</p>
|
||||
</div>
|
||||
<div class="rounded-lg px-4 py-0.5 m-2 bg-white border border-gray-200">
|
||||
<p class="text-2xl font-black font-mono mb-0.5">{{ userInfo().getUserStatsDto.series }}×</p>
|
||||
<p class="text-[11px] font-semibold font-mono text-gray-400 mt-0">Séries max</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="px-1">
|
||||
<div class="rounded-lg px-4 py-0.5 m-2 bg-white border border-gray-200">
|
||||
<p class="text-2xl font-black font-mono mb-0.5">{{ userInfo().getUserStatsDto.totalLikes }}</p>
|
||||
<p class="text-[11px] font-semibold font-mono text-gray-400 mt-0">Total de likes</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,15 @@
|
||||
import {Component, input} from '@angular/core';
|
||||
import {IonicModule} from "@ionic/angular";
|
||||
import {GetUserDetailsDto, GetUserDto} from "../../services/api";
|
||||
|
||||
@Component({
|
||||
selector: 'app-generic-user-info',
|
||||
templateUrl: './generic-user-info.component.html',
|
||||
styleUrls: ['./generic-user-info.component.scss'],
|
||||
imports: [
|
||||
IonicModule
|
||||
]
|
||||
})
|
||||
export class GenericUserInfoComponent {
|
||||
userInfo = input.required<GetUserDetailsDto | GetUserDto>()
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
<div class="bg-white rounded-xl p-5 shadow-sm border border-gray-200">
|
||||
<form [formGroup]="groupForm">
|
||||
<ion-label class="text-xs text-gray-500 mb-1 block">
|
||||
Nom du groupe
|
||||
<ion-text color="danger">*</ion-text>
|
||||
</ion-label>
|
||||
<ion-item lines="none" class="rounded-xl border border-gray-200">
|
||||
<ion-input placeholder="Nom de ton groupe"
|
||||
[clearInput]="true"
|
||||
formControlName="label"
|
||||
class="text-gray-800">
|
||||
</ion-input>
|
||||
</ion-item>
|
||||
|
||||
<div class="space-y-3 mt-4 max-h-[50vh] overflow-y-auto">
|
||||
<ion-label class="text-sm text-gray-500 block">
|
||||
Ajouter des amis dans le groupe
|
||||
</ion-label>
|
||||
|
||||
@for (friend of friends(); track friend.friendId) {
|
||||
<ion-item lines="none" class="rounded-lg border border-gray-100">
|
||||
<ion-checkbox class="text-sm text-gray-700"
|
||||
[checked]="groupForm.value.userGroups?.includes(friend.friendId)"
|
||||
(ionChange)="selectFriends($event, friend.friendId)">
|
||||
{{ friend.username }}
|
||||
</ion-checkbox>
|
||||
</ion-item>
|
||||
}
|
||||
</div>
|
||||
|
||||
<ion-button expand="block"
|
||||
class="mt-6 rounded-xl font-medium"
|
||||
style="--background: #1f2937;"
|
||||
(click)="createGroup()">
|
||||
Créer un groupe
|
||||
</ion-button>
|
||||
</form>
|
||||
</div>
|
||||
@@ -0,0 +1,112 @@
|
||||
import {Component, inject, input, OnInit, output, signal} from '@angular/core';
|
||||
import {FormControl, FormGroup, FormsModule, ReactiveFormsModule, Validators} from "@angular/forms";
|
||||
import {IonicModule, LoadingController, ToastController} from "@ionic/angular";
|
||||
import {
|
||||
CreateGroupDto,
|
||||
CreateUserGroupDto,
|
||||
FriendsService,
|
||||
GetFriendDto,
|
||||
GetGroupDto,
|
||||
GroupsService
|
||||
} from "../../services/api";
|
||||
import {firstValueFrom} from "rxjs";
|
||||
|
||||
@Component({
|
||||
selector: 'app-group-form',
|
||||
templateUrl: './group-form.component.html',
|
||||
styleUrls: ['./group-form.component.scss'],
|
||||
imports: [
|
||||
FormsModule,
|
||||
ReactiveFormsModule,
|
||||
IonicModule
|
||||
]
|
||||
})
|
||||
export class GroupFormComponent implements OnInit {
|
||||
private friendsServices = inject(FriendsService);
|
||||
private groupsServices = inject(GroupsService);
|
||||
private loadCtrl = inject(LoadingController);
|
||||
private toastCtrl = inject(ToastController);
|
||||
|
||||
friends = signal<GetFriendDto[]>([]);
|
||||
newGroup = output<GetGroupDto>();
|
||||
|
||||
groupForm: FormGroup = new FormGroup({
|
||||
label: new FormControl<string>(null, [Validators.required]),
|
||||
userGroups: new FormControl<CreateUserGroupDto[]>(null, [Validators.required]),
|
||||
});
|
||||
|
||||
async ngOnInit() {
|
||||
const loading = await this.loadCtrl.create({
|
||||
message: 'Chargement...',
|
||||
spinner: 'lines-sharp-small'
|
||||
});
|
||||
await loading.present();
|
||||
|
||||
try {
|
||||
const friends = await firstValueFrom(this.friendsServices.getAllFriendsEndpoint());
|
||||
this.friends.set(friends);
|
||||
} catch {
|
||||
const toast = await this.toastCtrl.create({
|
||||
message: 'Impossible d\'afficher les amis du joueur',
|
||||
duration: 2000,
|
||||
color: 'danger'
|
||||
});
|
||||
await toast.present();
|
||||
}
|
||||
await loading.dismiss();
|
||||
}
|
||||
|
||||
selectFriends(event: any, friendId: number) {
|
||||
const current = this.groupForm.value.userGroups || [];
|
||||
|
||||
if (event.detail.checked) {
|
||||
this.groupForm.patchValue({
|
||||
userGroups: [...current, friendId]
|
||||
});
|
||||
} else {
|
||||
this.groupForm.patchValue({
|
||||
userGroups: current.filter((x: number) => x != friendId)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async createGroup() {
|
||||
if (this.groupForm.invalid) {
|
||||
this.groupForm.reset();
|
||||
|
||||
const toast = await this.toastCtrl.create({
|
||||
message: 'Tous les champs doivent être saisis',
|
||||
duration: 2000,
|
||||
color: 'danger'
|
||||
});
|
||||
await toast.present();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const createGroupDto: CreateGroupDto = {
|
||||
label: this.groupForm.value.label,
|
||||
userGroups: this.groupForm.value.userGroups.map((x: number) => ({
|
||||
userId: x
|
||||
}))
|
||||
};
|
||||
|
||||
try {
|
||||
const group = await firstValueFrom(this.groupsServices.createGroupEndpoint(createGroupDto));
|
||||
this.newGroup.emit(group);
|
||||
const toast = await this.toastCtrl.create({
|
||||
message: 'Le groupe a été crée',
|
||||
duration: 2000,
|
||||
color: 'success'
|
||||
});
|
||||
await toast.present();
|
||||
} catch (e) {
|
||||
const toast = await this.toastCtrl.create({
|
||||
message: 'Impossible de créer le groupe',
|
||||
duration: 2000,
|
||||
color: 'danger'
|
||||
});
|
||||
await toast.present();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
<div class="rounded-lg m-3 bg-white border border-gray-200 p-4 flex flex-col items-center text-center gap-2">
|
||||
<div class="w-16 h-16 rounded-full bg-gray-100 flex items-center justify-center">
|
||||
<ion-icon name="people-outline" class="text-3xl text-gray-600"></ion-icon>
|
||||
</div>
|
||||
|
||||
<ion-label class="text-lg font-mono">{{ group().label }}</ion-label>
|
||||
<ion-label class="text-[13px] font-mono text-gray-400">{{ date() }}</ion-label>
|
||||
</div>
|
||||
|
||||
<app-title-part textInfo="Participants"></app-title-part>
|
||||
<div class="rounded-lg px-5 m-3 bg-white border border-gray-200 items-center">
|
||||
@for (user of group().users; track user.id; let i = $index) {
|
||||
@if (group().users.length - 1 == i) {
|
||||
<ion-item lines="none">
|
||||
<p class="text-sm text-gray-600 mr-2">{{ user.username }}</p>
|
||||
@if (user.grade === 'Admin') {
|
||||
<i class="fa-solid fa-crown text-xs text-yellow-600"></i>
|
||||
}
|
||||
<div class="flex items-center justify-end gap-1 w-full">
|
||||
@if (user.grade == 'Member') {
|
||||
<ion-icon class="text-2xl text-green-800 cursor-pointer" name="arrow-up-circle-outline"
|
||||
(click)="promoteUser(user.id)"></ion-icon>
|
||||
<app-pipe></app-pipe>
|
||||
}
|
||||
<ion-icon class="text-xl text-red-800 cursor-pointer" name="ban"
|
||||
(click)="deleteUser(user.id)"></ion-icon>
|
||||
</div>
|
||||
</ion-item>
|
||||
} @else {
|
||||
<ion-item lines="full">
|
||||
<p class="text-sm text-gray-600 mr-2">{{ user.username }}</p>
|
||||
@if (user.grade === 'Admin') {
|
||||
<i class="fa-solid fa-crown text-xs text-yellow-600"></i>
|
||||
}
|
||||
<div class="flex items-center justify-end gap-1 w-full">
|
||||
@if (user.grade == 'Member') {
|
||||
<ion-icon class="text-2xl text-green-800 cursor-pointer" name="arrow-up-circle-outline"
|
||||
(click)="promoteUser(user.id)"></ion-icon>
|
||||
<app-pipe></app-pipe>
|
||||
}
|
||||
<ion-icon class="text-xl text-red-800 cursor-pointer" name="ban"
|
||||
(click)="deleteUser(user.id)"></ion-icon>
|
||||
</div>
|
||||
</ion-item>
|
||||
}
|
||||
}
|
||||
</div>
|
||||
|
||||
<app-title-part textInfo="Paramètres"></app-title-part>
|
||||
<div class="rounded-lg px-5 m-3 bg-white border border-gray-200 items-center">
|
||||
<ion-list>
|
||||
@for (n of options; track n) {
|
||||
@if (n == options.length) {
|
||||
<ion-item lines="none" class="transition-all duration-200 active:[--background:#DBD8D7]"
|
||||
(click)="leaveGroup()">
|
||||
<p class="text-sm text-red-800">Quitter le groupe</p>
|
||||
<ion-icon slot="end" class="text-xl text-red-800" name="logout"></ion-icon>
|
||||
</ion-item>
|
||||
} @else {
|
||||
<ion-item lines="full" class="transition-all duration-200 active:[--background:#DBD8D7]"
|
||||
(click)="deleteGroup()">
|
||||
<p class="text-sm text-red-800">Supprimer le groupe</p>
|
||||
<ion-icon slot="end" class="text-xl text-red-800" name="chevron"></ion-icon>
|
||||
</ion-item>
|
||||
}
|
||||
}
|
||||
</ion-list>
|
||||
</div>
|
||||
@@ -0,0 +1,161 @@
|
||||
import {Component, computed, inject, input, OnInit, output, signal} from '@angular/core';
|
||||
import {GetGroupDetailsDto, GroupsService} from "../../services/api";
|
||||
import {addIcons} from "ionicons";
|
||||
import {peopleOutline, banOutline, arrowUpCircleOutline} from "ionicons/icons";
|
||||
import {IonicModule, LoadingController, ToastController} from "@ionic/angular";
|
||||
import moment from 'moment';
|
||||
import {TitlePartComponent} from "../title-part/title-part.component";
|
||||
import {firstValueFrom} from "rxjs";
|
||||
import {PipeComponent} from "../pipe/pipe.component";
|
||||
|
||||
addIcons({
|
||||
'avatars': peopleOutline,
|
||||
'ban': banOutline,
|
||||
'arrow-up-circle-outline': arrowUpCircleOutline,
|
||||
})
|
||||
|
||||
@Component({
|
||||
selector: 'app-group-info',
|
||||
templateUrl: './group-info.component.html',
|
||||
styleUrls: ['./group-info.component.scss'],
|
||||
imports: [
|
||||
IonicModule,
|
||||
TitlePartComponent,
|
||||
PipeComponent
|
||||
]
|
||||
})
|
||||
export class GroupInfoComponent implements OnInit {
|
||||
private groupsService = inject(GroupsService);
|
||||
private toastCtrl = inject(ToastController);
|
||||
private loadCtrl = inject(LoadingController);
|
||||
groupSelected = input.required<GetGroupDetailsDto>();
|
||||
group = signal<GetGroupDetailsDto>({});
|
||||
|
||||
date = computed<string>(() => moment(this.group().creationDate).format('DD/MM/YYYY'));
|
||||
|
||||
idGroup = output<number>();
|
||||
|
||||
options = [1, 2];
|
||||
|
||||
ngOnInit() {
|
||||
this.group.set(this.groupSelected());
|
||||
}
|
||||
|
||||
async deleteUser(id: number) {
|
||||
const loading = await this.loadCtrl.create({
|
||||
message: 'Suppression...',
|
||||
spinner: 'lines-sharp-small'
|
||||
});
|
||||
await loading.present();
|
||||
|
||||
try {
|
||||
await firstValueFrom(this.groupsService.deleteUserFromGroupEndpoint(this.group().id, id));
|
||||
this.group.update(x => ({
|
||||
...x,
|
||||
users: x.users.filter(u => u.id != id)
|
||||
}));
|
||||
const toast = await this.toastCtrl.create({
|
||||
message: 'Utilisateur retiré du groupe',
|
||||
duration: 2000,
|
||||
color: 'success'
|
||||
});
|
||||
await toast.present();
|
||||
} catch (e) {
|
||||
const toast = await this.toastCtrl.create({
|
||||
message: 'Vous devez être administrateur pour faire cela',
|
||||
duration: 2000,
|
||||
color: 'danger'
|
||||
});
|
||||
await toast.present();
|
||||
}
|
||||
await loading.dismiss();
|
||||
}
|
||||
|
||||
async leaveGroup() {
|
||||
const loading = await this.loadCtrl.create({
|
||||
message: 'Chargement...',
|
||||
spinner: 'lines-sharp-small'
|
||||
});
|
||||
await loading.present();
|
||||
|
||||
const oldGroup = this.group().id;
|
||||
|
||||
try {
|
||||
await firstValueFrom(this.groupsService.leaveGroupEndpoint(oldGroup));
|
||||
this.idGroup.emit(oldGroup);
|
||||
const toast = await this.toastCtrl.create({
|
||||
message: 'Vous avez quitter ce groupe',
|
||||
duration: 2000,
|
||||
color: 'success'
|
||||
});
|
||||
await toast.present();
|
||||
} catch {
|
||||
const toast = await this.toastCtrl.create({
|
||||
message: 'Impossible de quitter le groupe',
|
||||
duration: 2000,
|
||||
color: 'danger'
|
||||
});
|
||||
await toast.present();
|
||||
}
|
||||
await loading.dismiss();
|
||||
}
|
||||
|
||||
addToGroup() {
|
||||
}
|
||||
|
||||
async deleteGroup() {
|
||||
const loading = await this.loadCtrl.create({
|
||||
message: 'Suppression...',
|
||||
spinner: 'lines-sharp-small'
|
||||
});
|
||||
await loading.present();
|
||||
|
||||
const oldGroup = this.group().id;
|
||||
|
||||
try {
|
||||
await firstValueFrom(this.groupsService.deleteGroupEndpoint(oldGroup));
|
||||
this.idGroup.emit(oldGroup);
|
||||
const toast = await this.toastCtrl.create({
|
||||
message: 'Groupe supprimé',
|
||||
duration: 2000,
|
||||
color: 'success'
|
||||
});
|
||||
await toast.present();
|
||||
} catch (e) {
|
||||
const toast = await this.toastCtrl.create({
|
||||
message: 'Vous devez être administrateur pour faire cela',
|
||||
duration: 2000,
|
||||
color: 'danger'
|
||||
});
|
||||
await toast.present();
|
||||
}
|
||||
await loading.dismiss();
|
||||
}
|
||||
|
||||
async promoteUser(id: number) {
|
||||
const loading = await this.loadCtrl.create({
|
||||
message: 'Promotion...',
|
||||
spinner: 'lines-sharp-small'
|
||||
});
|
||||
await loading.present();
|
||||
|
||||
try {
|
||||
const group = await firstValueFrom(this.groupsService.patchGroupUserRoleEndpoint(this.group().id, id));
|
||||
this.group.set(group);
|
||||
const toast = await this.toastCtrl.create({
|
||||
message: 'Utilisateur promu avec succès',
|
||||
duration: 2000,
|
||||
color: 'success'
|
||||
});
|
||||
await toast.present();
|
||||
} catch (e) {
|
||||
const toast = await this.toastCtrl.create({
|
||||
message: 'Vous devez être administrateur pour faire cela',
|
||||
duration: 2000,
|
||||
color: 'danger'
|
||||
});
|
||||
await toast.present();
|
||||
}
|
||||
await loading.dismiss();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
<div class="rounded-lg m-3 bg-white border border-gray-200 items-center max-h-80 overflow-scroll">
|
||||
<ion-list>
|
||||
@if (groups().length) {
|
||||
@for (group of groups(); track group.id; let i = $index) {
|
||||
@if (i == groups().length - 1) {
|
||||
<ion-item lines="none"
|
||||
class="transition-all duration-200 active:[--background:#DBD8D7]"
|
||||
(click)="selectedGroup(group.id)">
|
||||
<p class="text-sm text-gray-600">{{ group.label }}</p>
|
||||
<ion-icon slot="end" class="text-xl text-gray-400" name="chevron"></ion-icon>
|
||||
</ion-item>
|
||||
} @else {
|
||||
<ion-item lines="full"
|
||||
class="transition-all duration-200 active:[--background:#DBD8D7]"
|
||||
(click)="selectedGroup(group.id)">
|
||||
<p class="text-sm text-gray-600">{{ group.label }}</p>
|
||||
<ion-icon slot="end" class="text-xl text-gray-400" name="chevron"></ion-icon>
|
||||
</ion-item>
|
||||
}
|
||||
}
|
||||
} @else {
|
||||
<ion-item lines="none" class="border border-stone-200 rounded-xl m-3" style="--background: #fafaf8;">
|
||||
<div class="flex flex-col items-center w-full px-10 py-20 gap-3">
|
||||
<div class="w-10 h-10 rounded-full bg-stone-100 border border-stone-200 flex items-center justify-center">
|
||||
<ion-icon name="group" style="color:#a8a090; font-size:20px;"></ion-icon>
|
||||
</div>
|
||||
<div class="text-center">
|
||||
<p class="m-0 text-sm font-medium text-stone-400">Pas encore de groupes</p>
|
||||
<p class="m-0 mt-1 text-xs text-stone-300 leading-relaxed">Vos groupes apparaîtront ici</p>
|
||||
</div>
|
||||
</div>
|
||||
</ion-item>
|
||||
}
|
||||
</ion-list>
|
||||
</div>
|
||||
@@ -0,0 +1,50 @@
|
||||
import {Component, inject, input, output} from '@angular/core';
|
||||
import {IonicModule, LoadingController, ToastController} from "@ionic/angular";
|
||||
import {GetGroupDetailsDto, GetGroupDto, GroupsService} from "../../services/api";
|
||||
import {addIcons} from "ionicons";
|
||||
import {chatbubblesOutline, chevronForwardOutline} from "ionicons/icons";
|
||||
import {firstValueFrom} from "rxjs";
|
||||
|
||||
addIcons({
|
||||
'group': chatbubblesOutline,
|
||||
'chevron': chevronForwardOutline,
|
||||
});
|
||||
|
||||
@Component({
|
||||
selector: 'app-groups',
|
||||
templateUrl: './groups.component.html',
|
||||
styleUrls: ['./groups.component.scss'],
|
||||
imports: [
|
||||
IonicModule
|
||||
]
|
||||
})
|
||||
export class GroupsComponent {
|
||||
private groupsService = inject(GroupsService);
|
||||
private toastCtrl = inject(ToastController);
|
||||
private loadCtrl = inject(LoadingController);
|
||||
|
||||
groups = input.required<GetGroupDto[]>();
|
||||
|
||||
group = output<GetGroupDetailsDto>();
|
||||
|
||||
async selectedGroup(id: number) {
|
||||
const loading = await this.loadCtrl.create({
|
||||
message: 'Chargement...',
|
||||
spinner: 'lines-sharp-small'
|
||||
});
|
||||
await loading.present();
|
||||
|
||||
try {
|
||||
const group = await firstValueFrom(this.groupsService.getGroupDetailsEndpoint(id));
|
||||
this.group.emit(group);
|
||||
} catch {
|
||||
const toast = await this.toastCtrl.create({
|
||||
message: 'Impossible de charger le groupe',
|
||||
duration: 2000,
|
||||
color: 'danger'
|
||||
});
|
||||
await toast.present();
|
||||
}
|
||||
await loading.dismiss();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
<form [formGroup]="messageForm">
|
||||
<ion-item lines="none" class="rounded-2xl border border-stone-200 mt-2">
|
||||
<ion-input placeholder="Envoyer un message..." formControlName="libelle"></ion-input>
|
||||
<ion-button style="--background: white" (click)="sendMessageOnGroup()">
|
||||
<ion-icon name="send-outline" class="text-xl text-stone-400"></ion-icon>
|
||||
</ion-button>
|
||||
</ion-item>
|
||||
</form>
|
||||