Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/import and user settings #260

Merged
merged 20 commits into from
Jul 20, 2024
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
node_modules
npm-debug.log
yarn-error.log
.git
.gitignore
.dockerignore
Dockerfile
*.md
.vscode
.idea
.env
.env.*
build
3 changes: 2 additions & 1 deletion .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ node_modules/
.env
.env.*
!.env.example

**/*.lockb
**/*ignore
# Ignore files for PNPM, NPM and YARN
pnpm-lock.yaml
package-lock.json
Expand Down
27 changes: 27 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
FROM node:20-alpine

# Install pnpm
RUN npm install -g pnpm

WORKDIR /app

COPY . .

# Install dependencies
RUN pnpm install --frozen-lockfile

# Copy the rest of the application code
COPY . .


ARG VITE_BACKEND_URL
ENV VITE_BACKEND_URL=$VITE_BACKEND_URL

# Build the application
RUN pnpm run build

# Expose the port the app runs on
EXPOSE 8080

# Command to run the application
CMD ["pnpm", "run", "preview"]
Binary file added bun.lockb
Binary file not shown.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
"layerchart": "^0.43.7",
"lucide-svelte": "^0.408.0",
"mode-watcher": "^0.4.0",
"simple-icons": "^13.1.0",
"socket.io": "^4.7.5",
"socket.io-client": "^4.7.5",
"svelte-i18next": "^2.2.2",
Expand Down
9 changes: 9 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion src/lib/components/navigator/Sidebar.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,9 @@
icon={mdiLogout}
{isSidebarOpen}
link=""
on:click={() => backend.auth.logout()}
on:click={() => {
backend.auth.logout();
}}
title={$i18n.t('navigation.logout')}
/>
{:else}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,11 @@
import { AlertDescription, AlertTitle } from '$lib/components/ui/alert/index.js';
import Icon from '$lib/components/ui/icon/icon.svelte';
import { mdiTranslate } from '@mdi/js';
import BackendService from '$lib/services/backend';

let selectedLanguage = get(i18n).language;

const backend = BackendService.getInstance();
$: createConfigMutation = backend.user.updateConfig();
let isDialogOpen = false;

const languages = Object.keys(get(i18n).options.resources ?? {});
Expand Down Expand Up @@ -68,6 +70,9 @@
const saveLanguage = () => {
$i18n.changeLanguage(selectedLanguage);
isDialogOpen = false;
$createConfigMutation.mutate({
config: { preferedLanguage: selectedLanguage.toLowerCase() }
});
};

const openDialog = () => {
Expand Down
10 changes: 5 additions & 5 deletions src/lib/components/ui/card/index.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import Root from './card.svelte';
import Content from './card-content.svelte';
import Description from './card-description.svelte';
import Footer from './card-footer.svelte';
import Header from './card-header.svelte';
import Title from './card-title.svelte';
import Content from './CardContent.svelte';
import Description from './CardDescription.svelte';
import Footer from './CardFooter.svelte';
import Header from './CardHeader.svelte';
import Title from './CardTitle.svelte';

export {
Root,
Expand Down
3 changes: 2 additions & 1 deletion src/lib/components/ui/icon-button/IconButton.svelte
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
<script lang="ts">
import Icon from '$lib/components/ui/icon/icon.svelte';
import { Button } from '$lib/components/ui/button/index.js';
import type { SimpleIcon } from 'simple-icons';

export let icon: string = '';
export let icon: SimpleIcon | string;
LudovicMalot marked this conversation as resolved.
Show resolved Hide resolved

export let contentClass = '';
</script>
Expand Down
137 changes: 137 additions & 0 deletions src/lib/components/user/NewAccountForm.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
<script lang="ts">
import { Button } from '$lib/components/ui/button';
import { Input } from '$lib/components/ui/input';
import { Label } from '$lib/components/ui/label';
import { AlertCircle } from 'lucide-svelte';
import { Alert, AlertDescription, AlertTitle } from '$lib/components/ui/alert';
import { Checkbox } from '$lib/components/ui/checkbox';
import H3 from '$lib/components/typography/H3.svelte';

import langFlagDE from '$lib/assets/languages/DE.svg';
import langFlagEN from '$lib/assets/languages/EN.svg';
import langFlagES from '$lib/assets/languages/ES.svg';
import langFlagFR from '$lib/assets/languages/FR.svg';
import langFlagIT from '$lib/assets/languages/IT.svg';
import langFlagPT from '$lib/assets/languages/PT.svg';
import langFlagPL from '$lib/assets/languages/PL.svg';
import langFlagRU from '$lib/assets/languages/RU.svg';
import langFlagTH from '$lib/assets/languages/TH.svg';
import langFlagZHS from '$lib/assets/languages/ZHS.svg';
import langFlagZHT from '$lib/assets/languages/ZHT.svg';

// Props
export let onSubmit: (data: { user: UserData; config: ConfigData }) => void;

const languages = [
{ code: 'en', name: 'English', flag: langFlagEN },
{ code: 'de', name: 'Deutsch', flag: langFlagDE },
{ code: 'es', name: 'Español', flag: langFlagES },
{ code: 'fr', name: 'Français', flag: langFlagFR },
{ code: 'it', name: 'Italiano', flag: langFlagIT },
{ code: 'pt', name: 'Português', flag: langFlagPT },
{ code: 'pl', name: 'Polski', flag: langFlagPL },
{ code: 'ru', name: 'Русский', flag: langFlagRU },
{ code: 'th', name: 'ไทย', flag: langFlagTH },
{ code: 'zh-CN', name: '简体中文', flag: langFlagZHS },
{ code: 'zh-TW', name: '繁體中文', flag: langFlagZHT }
];

interface UserData {
uid: number;
}

interface ConfigData {
autoRefine3: boolean;
autoRefine4: boolean;
autoRefine5: boolean;
preferedLanguage: string;
}

let user: UserData = {
uid: 1
};

let config: ConfigData = {
autoRefine3: false,
autoRefine4: false,
autoRefine5: false,
preferedLanguage: 'en'
};

let errors: Partial<{ uid: string }> = {};

function validateForm(): boolean {
errors = {};
if (!user.uid || user.uid < 100000000 || user.uid > 999999999) {
errors.uid = 'UID must be a 9-digit number';
}
return Object.keys(errors).length === 0;
}

function handleSubmit() {
if (!validateForm()) {
return;
}
onSubmit({ user, config });
}
</script>

<form on:submit|preventDefault={handleSubmit} class="space-y-4 col-span-2 p-5">
{#if Object.keys(errors).length > 0}
<Alert variant="destructive" class="mt-4">
<AlertCircle class="h-4 w-4" />
<AlertTitle>Error</AlertTitle>
<AlertDescription>
Please correct the errors in the form before submitting.
</AlertDescription>
</Alert>
{/if}
<div>
<Label for="uid">UID</Label>
<Input type="number" id="uid" bind:value={user.uid} />
{#if errors.uid}
<p class="text-red-500 text-sm mt-1">{errors.uid}</p>
{/if}
</div>
<H3>Add configuration information (optional)</H3>
<div>
<Label>Auto Refine Settings</Label>
<div class="space-y-2">
<div class="flex items-center space-x-2">
<Checkbox bind:checked={config.autoRefine3} id="autoRefine3" />
<label for="autoRefine3">Auto Refine 3-star weapons</label>
</div>
<div class="flex items-center space-x-2">
<Checkbox bind:checked={config.autoRefine4} id="autoRefine4" />
<label for="autoRefine4">Auto Refine 4-star weapons</label>
</div>
<div class="flex items-center space-x-2">
<Checkbox bind:checked={config.autoRefine5} id="autoRefine5" />
<label for="autoRefine5">Auto Refine 5-star weapons</label>
</div>
</div>
</div>

<div>
<Label for="language">Preferred Language</Label>
<div class="grid grid-cols-2 gap-2 mt-2">
{#each languages as lang}
<Button
type="button"
variant={config.preferedLanguage === lang.code ? 'default' : 'outline'}
class="flex items-center justify-start space-x-2"
on:click={() => (config.preferedLanguage = lang.code)}
>
<img src={lang.flag} alt={lang.name} class="w-6 h-4" />
<span>{lang.name}</span>
</Button>
{/each}
</div>
</div>

<div class="flex space-x-4">
<Button type="submit" class="flex-1 bg-primary text-primary-foreground">
Complete Profile
</Button>
</div>
</form>
27 changes: 27 additions & 0 deletions src/lib/locales/EN.json
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,28 @@
"characters.detailed.category.builds.artifacts.main_stats.title": "Main Stats",
"characters.detailed.category.builds.artifacts.sub_stats.title": "Sub stats",
"characters.detailed.category.builds.talents.title": "Talents",
"welcome.title": "Welcome, Traveler!",
"profile.complete.title": "Complete Your Profile to Unlock Full Features",
"profile.complete.description": "By completing your profile, you'll gain access to enhanced features and personalized experiences. Once logged in, you'll be able to import data from various sources and export your information securely.",
"profile.create.success": "Profile created successfully!",
"profile.create.error": "Error creating profile: {error}",
"profile.create.pending.title": "Creating Your Profile",
"profile.create.pending.description": "Please wait while we set up your personalized experience...",
"profile.create.error.title": "Profile Creation Error",
"settings.overview.title": "Settings",
"settings.category.theming.title": "Theming",
"settings.category.data.title": "Data",
"settings.category.data.import_data_button": "Import data",
"settings.category.data.export_data_button": "Export data",
"settings.login_providers": "Login providers",
"settings.auto_refine_settings": "Auto Refine Settings",
"settings.auto_refine_3_star": "Auto Refine 3-star weapons",
"settings.auto_refine_4_star": "Auto Refine 4-star weapons",
"settings.auto_refine_5_star": "Auto Refine 5-star weapons",
"settings.save_settings": "Save Settings",
"settings.delete_account": "Delete account",
"settings.delete_account_confirmation": "Are you sure you want to delete your account? This action is irreversible and all data will be lost.",
"settings.delete_account_confirm": "Delete account",
"settings.import.title": "Import account data",
"settings.import.no_file_selected": "No file selected",
"settings.import.warning.title": "Watch out!",
Expand All @@ -76,6 +93,8 @@
"settings.import.confirmation_dialog.title": "Are you sure?",
"settings.import.confirmation_dialog.description": "Lorem ipsum dolor sit amet consectetur adipisicing elit. Vitae deserunt velit autem veniam doloribus nulla. Culpa fugiat nemo accusantium cumque soluta tenetur tempora veritatis magnam nulla aliquid. Similique, perspiciatis unde?",
"login.title": "Be able to do more with an account!",
"login.alert.title": "Important: Local Data Notice",
"login.alert.description": "Logging in will overwrite your local data. Please ensure you've backed up any important information before proceeding.",
"login.perk.cross_device_sync.title": "Cross-device synchronization",
"login.perk.cross_device_sync.description": "Lorem ipsum dolor sit amet consectetur adipisicing elit. Vitae deserunt velit autem veniam doloribus nulla. Culpa fugiat nemo accusantium cumque soluta tenetur tempora veritatis magnam nulla aliquid. Similique, perspiciatis unde?",
"login.perk.server_access.title": "Access to server side functions",
Expand All @@ -98,6 +117,14 @@
"server.wish_history.active": "Your wish history is now being processed",
"server.wish_history.success": "Your wish history was successfully imported",
"server.wish_history.error": "Your wish history failed to import",
"action.reset_filters": "Reset Filters",
"filter.element": "Element",
"filter.weapon": "Weapon",
"filter.rarity": "Rarity",
"filter.owned": "Owned",
"sort.name": "Name",
"sort.date": "Date",
"sort.constellation": "Constellation",
"language.DE": "Deutsch",
"language.EN": "English",
"language.ES": "Español",
Expand Down
4 changes: 4 additions & 0 deletions src/lib/services/backend/auth.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { applicationState } from '$lib/store/application_state';
import { userProfile, defaultValues } from '$lib/store/user_profile';

export class BackendAuthService {
private readonly baseUrl: string;
Expand All @@ -16,6 +17,9 @@ export class BackendAuthService {
state.isAuthenticated = false;
return state;
});
userProfile.update(() => {
return defaultValues;
});
window.location.href = `${this.baseUrl}/logout`;
}

Expand Down
6 changes: 3 additions & 3 deletions src/lib/services/backend/hoyo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export class BackendHoyoService {
{
mutationFn: (authkey: string) =>
backendFetch<FetchHoyoWishHistoryResponse>(
`${this.baseUrl}/wishhistory?authkey=${authkey}`
`${this.baseUrl}/wish?authkey=${authkey}`
)
},
this.queryClient
Expand All @@ -46,7 +46,7 @@ export class BackendHoyoService {
fetchHoyoWishHistoryStatus() {
return createQuery<BackendStateResponse | FetchHoyoWishHistoryStatusResponse>(
derived(applicationState, (appState) => ({
queryKey: ['fetchHoyoWishhistoryStatus', appState.isAuthenticated],
queryKey: ['fetchHoyoWishStatus', appState.isAuthenticated],
staleTime: 60 * 60 * 1000, //1h
queryFn: async () =>
await backendFetch<FetchHoyoWishHistoryStatusResponse>(
Expand All @@ -59,6 +59,6 @@ export class BackendHoyoService {
}

getHoyoWishHistoryStatusUrl() {
return `${this.baseUrl}/wishhistory/status`;
return `${this.baseUrl}/wish/status`;
}
}
Loading