From 7dc3dedda5db85d17f64cef115a17309e1d42143 Mon Sep 17 00:00:00 2001 From: chamikaJ Date: Fri, 25 Jul 2025 12:50:19 +0530 Subject: [PATCH] feat(account-setup): enhance localization and UI for account setup process - Added new language support and improved translations for account setup steps across multiple languages. - Updated the organization step to streamline user input and enhance suggestions for organization names. - Refactored task management components to improve user experience when adding and managing tasks. - Removed outdated CSS for admin center components to simplify styling and improve maintainability. - Introduced new UI elements and transitions for a more engaging account setup experience. - Enhanced Redux state management to accommodate new features and localization updates. --- .claude/settings.local.json | 3 +- .../src/public/locales/en/account-setup.json | 2 +- .../public/locales/alb/account-setup.json | 282 ++++++++----- .../public/locales/de/account-setup.json | 62 ++- .../de/admin-center/configuration.json | 26 ++ .../public/locales/en/account-setup.json | 66 ++- .../en/admin-center/configuration.json | 26 ++ .../locales/en/admin-center/current-bill.json | 23 +- .../locales/en/admin-center/overview.json | 5 +- .../public/locales/en/admin-center/users.json | 3 +- .../public/locales/es/account-setup.json | 62 ++- .../public/locales/pt/account-setup.json | 62 ++- .../public/locales/zh/account-setup.json | 62 ++- .../account-setup/admin-center-common.css | 19 - .../components/account-setup/members-step.tsx | 106 ++--- .../account-setup/organization-step.tsx | 108 +---- .../components/account-setup/project-step.tsx | 298 +++++++------- .../components/account-setup/survey-step.tsx | 240 +++-------- .../components/account-setup/tasks-step.tsx | 68 +--- .../template-drawer/template-drawer.tsx | 92 ++++- .../src/pages/account-setup/account-setup.css | 384 +++--------------- .../src/pages/account-setup/account-setup.tsx | 77 +++- 22 files changed, 1003 insertions(+), 1073 deletions(-) create mode 100644 worklenz-frontend/public/locales/de/admin-center/configuration.json create mode 100644 worklenz-frontend/public/locales/en/admin-center/configuration.json delete mode 100644 worklenz-frontend/src/components/account-setup/admin-center-common.css diff --git a/.claude/settings.local.json b/.claude/settings.local.json index 8d88ae97..7170befa 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -6,7 +6,8 @@ "Bash(npm run type-check:*)", "Bash(npm run:*)", "Bash(move:*)", - "Bash(mv:*)" + "Bash(mv:*)", + "Bash(rm:*)" ], "deny": [] } diff --git a/worklenz-backend/src/public/locales/en/account-setup.json b/worklenz-backend/src/public/locales/en/account-setup.json index 5e71ca40..4310e0c6 100644 --- a/worklenz-backend/src/public/locales/en/account-setup.json +++ b/worklenz-backend/src/public/locales/en/account-setup.json @@ -1,7 +1,7 @@ { "continue": "Continue", - "setupYourAccount": "Setup Your Worklenz Account.", + "setupYourAccount": "Setup Your Account.", "organizationStepTitle": "Name Your Organization", "organizationStepLabel": "Pick a name for your Worklenz account.", diff --git a/worklenz-frontend/public/locales/alb/account-setup.json b/worklenz-frontend/public/locales/alb/account-setup.json index 21c50f1d..2f811092 100644 --- a/worklenz-frontend/public/locales/alb/account-setup.json +++ b/worklenz-frontend/public/locales/alb/account-setup.json @@ -1,119 +1,191 @@ { "continue": "Vazhdo", - "setupYourAccount": "Konfiguro Llogarinë Tënde në Worklenz.", - "organizationStepTitle": "Emërtoni Organizatën Tuaj", - "organizationStepLabel": "Zgjidhni një emër për llogarinë tuaj në Worklenz.", - "organizationStepWelcome": "Setup Your Worklenz Account.", - "organizationStepDescription": "Let's start by setting up your organization. This will be the main workspace for your team.", - "organizationStepTooltip": "This name will appear in your workspace and can be changed later in settings.", - "organizationStepNeedIdeas": "Need ideas?", - "organizationStepUseDetected": "Use detected:", - "organizationStepCharacters": "characters", - "organizationStepGoodLength": "Good length", - "organizationStepTooShort": "Too short", - "organizationStepNamingTips": "Naming Tips", - "organizationStepTip1": "Keep it simple and memorable", - "organizationStepTip2": "Reflect your industry or values", - "organizationStepTip3": "Think about future growth", - "organizationStepTip4": "Make it unique and brandable", - "organizationStepSuggestionsTitle": "Name Suggestions", - "organizationStepCategory1": "Tech Companies", - "organizationStepCategory2": "Creative Agencies", - "organizationStepCategory3": "Consulting", - "organizationStepCategory4": "Startups", - "organizationStepSuggestionsNote": "These are just examples to get you started. Choose something that represents your organization.", - "organizationStepPrivacyNote": "Your organization name is private and only visible to your team members.", - "step2Title": "Create your first tasks", - "step2InputLabel": "Type a few tasks that you are going to do in", - "step2AddAnother": "Add another", - "formTitle": "Create your first task.", - "step3Title": "Invite your team to work with", - "orgTypeQuestion": "What best describes your organization?", - "userRoleQuestion": "What's your role?", - "yourNeedsTitle": "What are your main needs?", - "yourNeedsDescription": "Select all that apply to help us set up your workspace", - "yourNeedsQuestion": "How will you primarily use Worklenz?", - "useCaseTaskOrg": "Organize and track tasks", - "useCaseTeamCollab": "Work together seamlessly", - "useCaseResourceMgmt": "Manage time and resources", - "useCaseClientComm": "Stay connected with clients", - "useCaseTimeTrack": "Monitor project hours", - "useCaseOther": "Something else", - "selectedText": "selected", - "previousToolsQuestion": "What tools have you used before? (Optional)", - "previousToolsPlaceholder": "e.g., Asana, Trello, Jira, Monday.com, etc.", - "discoveryTitle": "One last thing...", - "discoveryDescription": "Help us understand how you discovered Worklenz", - "discoveryQuestion": "How did you hear about us?", - "allSetTitle": "You're all set!", - "allSetDescription": "Let's create your first project and get started with Worklenz", - "aboutYouStepName": "About You", - "yourNeedsStepName": "Your Needs", - "discoveryStepName": "Discovery", - "stepProgress": "Step {step} of 3: {title}", - "projectStepHeader": "Let's create your first project", - "projectStepSubheader": "Start from scratch or use a template to get going faster", - "startFromScratch": "Start from scratch", - "templateSelected": "Template selected below", - "quickSuggestions": "Quick suggestions:", - "orText": "OR", - "startWithTemplate": "Start with a template", - "clearToSelectTemplate": "Clear project name above to select a template", - "templateHeadStart": "Get a head start with pre-built project structures", - "browseAllTemplates": "Browse All Templates", - "templatesAvailable": "15+ industry-specific templates available", - "chooseTemplate": "Choose a template that matches your project type", - "createProject": "Create Project", - "templateSoftwareDev": "Software Development", - "templateSoftwareDesc": "Agile sprints, bug tracking, releases", - "templateMarketing": "Marketing Campaign", - "templateMarketingDesc": "Campaign planning, content calendar", - "templateConstruction": "Construction Project", - "templateConstructionDesc": "Phases, permits, contractors", - "templateStartup": "Startup Launch", - "templateStartupDesc": "MVP development, funding, growth", - - "tasksStepTitle": "Shtoni detyrat tuaja të para", - "tasksStepDescription": "Ndani \"{projectName}\" në detyra të zbatueshe për të filluar", - "taskPlaceholder": "Detyra {index} - p.sh., Çfarë duhet bërë?", - "addAnotherTask": "Shtoni një detyrë tjetër ({current}/{max})", - - "surveyStepTitle": "Na tregoni për ju", - "surveyStepLabel": "Na ndihmoni të personalizojmë eksperiencën tuaj në Worklenz duke përgjigjur disa pyetjeve.", - - "organizationType": "Cila përshkruan më mirë organizatën tuaj?", + "setupYourAccount": "Konfiguro llogarinë tënde.", + "organizationStepTitle": "Emërto organizatën tënde", + "organizationStepLabel": "Zgjidh një emër për llogarinë tënde në Worklenz.", + "organizationStepWelcome": "Konfiguro llogarinë tënde në Worklenz.", + "organizationStepDescription": "Le të fillojmë duke konfiguruar organizatën tënde. Kjo do të jetë hapësira kryesore e punës për ekipin tënd.", + "organizationStepTooltip": "Ky emër do të shfaqet në hapësirën tënde të punës dhe mund të ndryshohet më vonë në cilësime.", + "organizationStepNeedIdeas": "Keni nevojë për ide?", + "organizationStepUseDetected": "Përdorimi i zbuluar:", + "organizationStepCharacters": "karaktere", + "organizationStepGoodLength": "Gjatësi e mirë", + "organizationStepTooShort": "Shumë i shkurtër", + "organizationStepNamingTips": "Këshilla për emërtimin", + "organizationStepTip1": "Mbaje të thjeshtë dhe të lehtë për t'u mbajtur mend", + "organizationStepTip2": "Përfaqëso industrinë ose vlerat e tua", + "organizationStepTip3": "Mendo për rritjen në të ardhmen", + "organizationStepTip4": "Bëje unik dhe të përshtatshëm për markë", + "organizationStepSuggestionsTitle": "Sugjerime për emra", + "organizationStepCategory1": "Kompani Teknologjie", + "organizationStepCategory2": "Agjenci Kreative", + "organizationStepCategory3": "Konsulencë", + "organizationStepCategory4": "Startupe", + "organizationStepSuggestionsNote": "Këto janë vetëm shembuj për të të ndihmuar të fillosh. Zgjidh diçka që përfaqëson organizatën tënde.", + "organizationStepPrivacyNote": "Emri i organizatës tënde është privat dhe i dukshëm vetëm për anëtarët e ekipit.", + "projectStepTitle": "Krijo projektin tënd të parë", + "projectStepLabel": "Në cilin projekt po punon tani?", + "projectStepPlaceholder": "p.sh. Plani i Marketingut", + "tasksStepTitle": "Krijo detyrat e tua të para", + "tasksStepLabel": "Shkruaj disa detyra që do të kryesh në", + "tasksStepAddAnother": "Shto një tjetër", + "emailPlaceholder": "Adresa e emailit", + "invalidEmail": "Ju lutem vendosni një adresë emaili të vlefshme", + "or": "ose", + "templateButton": "Importo nga shablloni", + "goBack": "Kthehu mbrapa", + "cancel": "Anulo", + "create": "Krijo", + "templateDrawerTitle": "Zgjidh nga shabllonet", + "step3InputLabel": "Fto me email", + "addAnother": "Shto një tjetër", + "skipForNow": "Kalo për tani", + "formTitle": "Krijo detyrën tënde të parë.", + "step3Title": "Fto ekipin tënd për të punuar së bashku", + "maxMembers": " (Mund të ftoni deri në 5 anëtarë)", + "maxTasks": " (Mund të krijoni deri në 5 detyra)", + "membersStepTitle": "Fto ekipin tënd", + "membersStepDescription": "Shto anëtarë ekipi në \"{{organizationName}}\" dhe filloni bashkëpunimin", + "memberPlaceholder": "Anëtari i ekipit {{index}} - Shkruani adresën e emailit", + "validEmailAddress": "Adresë emaili e vlefshme", + "addAnotherTeamMember": "Shto një anëtar tjetër të ekipit ({{current}}/{{max}})", + "canInviteLater": "Gjithmonë mund të ftoni anëtarë të ekipit më vonë", + "skipStepDescription": "Nuk i keni adresat e emailit gati? Asnjë problem! Mund ta kaloni këtë hap dhe të ftoni anëtarë nga paneli i projektit më vonë.", + "orgCategoryTech": "Kompani Teknologjie", + "orgCategoryCreative": "Agjenci Kreative", + "orgCategoryConsulting": "Konsulencë", + "orgCategoryStartups": "Startupe", + "namingTip1": "Mbaje të thjeshtë dhe të lehtë për t'u mbajtur mend", + "namingTip2": "Përfaqëso industrinë ose vlerat e tua", + "namingTip3": "Mendo për rritjen në të ardhmen", + "namingTip4": "Bëje unik dhe të përshtatshëm për markë", + "aboutYouTitle": "Na trego për veten tënde", + "aboutYouDescription": "Na ndihmo të personalizojmë përvojën tënde", + "orgTypeQuestion": "Cila përshkruan më mirë organizatën tënde?", + "userRoleQuestion": "Cili është roli yt?", + "yourNeedsTitle": "Cilat janë nevojat e tua kryesore?", + "yourNeedsDescription": "Zgjidh të gjitha që aplikohen për të na ndihmuar të konfigurojmë hapësirën tënde të punës", + "yourNeedsQuestion": "Si do ta përdorësh kryesisht Worklenz?", + "useCaseTaskOrg": "Organizo dhe ndiq detyrat", + "useCaseTeamCollab": "Puno së bashku pa pengesa", + "useCaseResourceMgmt": "Menaxho kohën dhe burimet", + "useCaseClientComm": "Qëndro i lidhur me klientët", + "useCaseTimeTrack": "Monitoro orët e projektit", + "useCaseOther": "Diçka tjetër", + "selectedText": "zgjedhur", + "previousToolsQuestion": "Çfarë mjetesh ke përdorur më parë? (Opsionale)", + "discoveryTitle": "Edhe një gjë e fundit...", + "discoveryDescription": "Na ndihmo të kuptojmë si e zbulove Worklenz", + "discoveryQuestion": "Si dëgjove për ne?", + "allSetTitle": "Çdo gjë gati!", + "allSetDescription": "Le të krijojmë projektin tënd të parë dhe të fillojmë me Worklenz", + "aboutYouStepName": "Rreth teje", + "yourNeedsStepName": "Nevojat e tua", + "discoveryStepName": "Zbulimi", + "stepProgress": "Hapi {step} nga 3: {title}", + "projectStepHeader": "Le të krijojmë projektin tënd të parë", + "projectStepSubheader": "Fillo nga e para ose përdor një shabllon për të filluar më shpejt", + "startFromScratch": "Fillo nga e para", + "templateSelected": "Shablloni i zgjedhur më poshtë", + "quickSuggestions": "Sugjerime të shpejta:", + "orText": "OSE", + "startWithTemplate": "Fillo me një shabllon", + "clearToSelectTemplate": "Pastro emrin e projektit më sipër për të zgjedhur një shabllon", + "templateHeadStart": "Fillo më shpejt me struktura të gatshme projekti", + "browseAllTemplates": "Shfleto të gjitha shabllonet", + "templatesAvailable": "15+ shabllone të specializuara sipas industrisë në dispozicion", + "chooseTemplate": "Zgjidh një shabllon që i përshtatet llojit të projektit tënd", + "createProject": "Krijo projekt", + "templateSoftwareDev": "Zhvillim Softueri", + "templateSoftwareDesc": "Sprint-e agile, ndjekje gabimesh, lëshime", + "templateMarketing": "Fushatë Marketingu", + "templateMarketingDesc": "Planifikim fushate, kalendar përmbajtjesh", + "templateConstruction": "Projekt Ndërtimi", + "templateConstructionDesc": "Faza, leje, kontraktorë", + "templateStartup": "Lansim Startup-i", + "templateStartupDesc": "Zhvillim MVP, financim, rritje", + "tasksStepDescription": "Ndaji \"{{projectName}}\" në detyra të veprueshme për të filluar", + "taskPlaceholder": "Detyra {{index}} - p.sh., Çfarë duhet bërë?", + "addAnotherTask": "Shto një detyrë tjetër ({{current}}/{{max}})", + "surveyStepTitle": "Na trego për veten tënde", + "surveyStepLabel": "Na ndihmo të personalizojmë përvojën tënde në Worklenz duke iu përgjigjur disa pyetjeve.", + "organizationType": "Cila përshkruan më mirë organizatën tënde?", "organizationTypeFreelancer": "Freelancer", "organizationTypeStartup": "Startup", - "organizationTypeSmallMediumBusiness": "Biznes i Vogël ose i Mesmu", - "organizationTypeAgency": "Agjensi", + "organizationTypeSmallMediumBusiness": "Biznes i Vogël ose i Mesëm", + "organizationTypeAgency": "Agjenci", "organizationTypeEnterprise": "Ndërmarrje", "organizationTypeOther": "Tjetër", - - "userRole": "Cili është roli juaj?", - "userRoleFounderCeo": "Themeluesi / CEO", - "userRoleProjectManager": "Menaxheri i Projektit", - "userRoleSoftwareDeveloper": "Zhvilluesi i Software-it", - "userRoleDesigner": "Dizajneri", + "userRole": "Cili është roli yt?", + "userRoleFounderCeo": "Themelues / CEO", + "userRoleProjectManager": "Menaxher Projekti", + "userRoleSoftwareDeveloper": "Zhvillues Softueri", + "userRoleDesigner": "Dizajner", "userRoleOperations": "Operacionet", "userRoleOther": "Tjetër", - - "mainUseCases": "Për çfarë do ta përdorni kryësisht Worklenz?", - "mainUseCasesTaskManagement": "Menaxhimi i detyrave", - "mainUseCasesTeamCollaboration": "Bashkëpunimi i ekipit", - "mainUseCasesResourcePlanning": "Planifikimi i burimeve", - "mainUseCasesClientCommunication": "Komunikimi me klientët & raportet", - "mainUseCasesTimeTracking": "Ndjekja e kohës", + "mainUseCases": "Për çfarë do ta përdorësh kryesisht Worklenz?", + "mainUseCasesTaskManagement": "Menaxhim detyrash", + "mainUseCasesTeamCollaboration": "Bashkëpunim ekipi", + "mainUseCasesResourcePlanning": "Planifikim burimesh", + "mainUseCasesClientCommunication": "Komunikim & raportim me klientët", + "mainUseCasesTimeTracking": "Ndjekje kohe", "mainUseCasesOther": "Tjetër", - - "previousTools": "Cilat vegla përdornit para Worklenz?", + "previousTools": "Çfarë mjetesh ke përdorur para Worklenz?", "previousToolsPlaceholder": "p.sh. Trello, Asana, Monday.com", - - "howHeardAbout": "Si dëgjuat për Worklenz?", - "howHeardAboutGoogleSearch": "Kërkimi Google", + "howHeardAbout": "Si dëgjove për Worklenz?", + "howHeardAboutGoogleSearch": "Kërkim në Google", "howHeardAboutTwitter": "Twitter", "howHeardAboutLinkedin": "LinkedIn", - "howHeardAboutFriendColleague": "Një miku ose kolegu", - "howHeardAboutBlogArticle": "Një blog ose artikulli", - "howHeardAboutOther": "Tjetër" + "howHeardAboutFriendColleague": "Një mik ose koleg", + "howHeardAboutBlogArticle": "Një blog ose artikull", + "howHeardAboutOther": "Tjetër", + + "aboutYouStepTitle": "Na trego për veten", + "aboutYouStepDescription": "Na ndihmo të personalizojmë përvojën tënde", + "yourNeedsStepTitle": "Cilat janë nevojat e tua kryesore?", + "yourNeedsStepDescription": "Zgjidh të gjitha që aplikohen për të na ndihmuar të konfigurojmë hapësirën tënde të punës", + "selected": "zgjedhur", + "previousToolsLabel": "Çfarë mjetesh ke përdorur më parë? (Opsionale)", + + "roleSuggestions": { + "designer": "UI/UX, Grafikë, Kreativ", + "developer": "Frontend, Backend, Full-stack", + "projectManager": "Planifikim, Koordinim", + "marketing": "Përmbajtje, Media Sociale, Rritje", + "sales": "Zhvillim Biznesi, Marrëdhënie me Klientë", + "operations": "Administratë, HR, Financa" + }, + + "languages": { + "en": "Anglisht", + "es": "Spanjisht", + "pt": "Portugalisht", + "de": "Gjermanisht", + "alb": "Shqip", + "zh": "Kinezçe" + }, + + "orgSuggestions": { + "tech": ["TechCorp", "DevStudio", "CodeCraft", "PixelForge"], + "creative": ["Creative Hub", "Design Studio", "Brand Works", "Visual Arts"], + "consulting": ["Strategy Group", "Business Solutions", "Expert Advisors", "Growth Partners"], + "startup": ["Innovation Labs", "Future Works", "Venture Co", "Next Gen"] + }, + + "projectSuggestions": { + "freelancer": ["Projekti i Klientit", "Përditësim Portfolio", "Markë Personale"], + "startup": ["Zhvillim MVP", "Lansim Produkti", "Kërkim Tregu"], + "agency": ["Fushatë Klienti", "Strategji Markë", "Ridizajnim Website"], + "enterprise": ["Migrim Sistemi", "Optimizim Procesesh", "Trajnim Ekipi"] + }, + + "useCaseDescriptions": { + "taskManagement": "Organizoj dhe ndjek detyrat", + "teamCollaboration": "Punojmë së bashku pa probleme", + "resourcePlanning": "Menaxhoj kohën dhe burimet", + "clientCommunication": "Qëndroj i lidhur me klientët", + "timeTracking": "Monitoroj orët e projektit", + "other": "Diçka tjetër" + } } diff --git a/worklenz-frontend/public/locales/de/account-setup.json b/worklenz-frontend/public/locales/de/account-setup.json index ecb37f48..9890bcc0 100644 --- a/worklenz-frontend/public/locales/de/account-setup.json +++ b/worklenz-frontend/public/locales/de/account-setup.json @@ -51,10 +51,10 @@ "maxTasks": " (Sie können bis zu 5 Aufgaben erstellen)", "membersStepTitle": "Laden Sie Ihr Team ein", - "membersStepDescription": "Teammitglieder zu \"{organizationName}\" hinzufügen und mit der Zusammenarbeit beginnen", - "memberPlaceholder": "Teammitglied {index} - E-Mail-Adresse eingeben", + "membersStepDescription": "Teammitglieder zu \"{{organizationName}}\" hinzufügen und mit der Zusammenarbeit beginnen", + "memberPlaceholder": "Teammitglied {{index}} - E-Mail-Adresse eingeben", "validEmailAddress": "Gültige E-Mail-Adresse", - "addAnotherTeamMember": "Weiteres Teammitglied hinzufügen ({current}/{max})", + "addAnotherTeamMember": "Weiteres Teammitglied hinzufügen ({{current}}/{{max}})", "canInviteLater": "Sie können Teammitglieder jederzeit später einladen", "skipStepDescription": "Haben Sie keine E-Mail-Adressen bereit? Kein Problem! Sie können diesen Schritt überspringen und Teammitglieder später über Ihr Projekt-Dashboard einladen.", @@ -119,9 +119,9 @@ "templateStartupDesc": "MVP-Entwicklung, Finanzierung, Wachstum", "tasksStepTitle": "Fügen Sie Ihre ersten Aufgaben hinzu", - "tasksStepDescription": "Unterteilen Sie \"{projectName}\" in umsetzbare Aufgaben, um zu beginnen", - "taskPlaceholder": "Aufgabe {index} - z.B., Was muss getan werden?", - "addAnotherTask": "Weitere Aufgabe hinzufügen ({current}/{max})", + "tasksStepDescription": "Unterteilen Sie \"{{projectName}}\" in umsetzbare Aufgaben, um zu beginnen", + "taskPlaceholder": "Aufgabe {{index}} - z.B., Was muss getan werden?", + "addAnotherTask": "Weitere Aufgabe hinzufügen ({{current}}/{{max}})", "surveyStepTitle": "Erzählen Sie uns von sich", "surveyStepLabel": "Helfen Sie uns, Ihre Worklenz-Erfahrung zu personalisieren, indem Sie ein paar Fragen beantworten.", @@ -159,5 +159,53 @@ "howHeardAboutLinkedin": "LinkedIn", "howHeardAboutFriendColleague": "Ein Freund oder Kollege", "howHeardAboutBlogArticle": "Ein Blog oder Artikel", - "howHeardAboutOther": "Andere" + "howHeardAboutOther": "Andere", + + "aboutYouStepTitle": "Erzählen Sie uns von sich", + "aboutYouStepDescription": "Helfen Sie uns, Ihre Erfahrung zu personalisieren", + "yourNeedsStepTitle": "Was sind Ihre Hauptbedürfnisse?", + "yourNeedsStepDescription": "Wählen Sie alle zutreffenden aus, um uns bei der Einrichtung Ihres Arbeitsbereichs zu helfen", + "selected": "ausgewählt", + "previousToolsLabel": "Welche Tools haben Sie zuvor verwendet? (Optional)", + + "roleSuggestions": { + "designer": "UI/UX, Grafiken, Kreativ", + "developer": "Frontend, Backend, Full-stack", + "projectManager": "Planung, Koordination", + "marketing": "Inhalt, Social Media, Wachstum", + "sales": "Geschäftsentwicklung, Kundenbeziehungen", + "operations": "Admin, HR, Finanzen" + }, + + "languages": { + "en": "English", + "es": "Español", + "pt": "Português", + "de": "Deutsch", + "alb": "Shqip", + "zh": "简体中文" + }, + + "orgSuggestions": { + "tech": ["TechCorp", "DevStudio", "CodeCraft", "PixelForge"], + "creative": ["Creative Hub", "Design Studio", "Brand Works", "Visual Arts"], + "consulting": ["Strategy Group", "Business Solutions", "Expert Advisors", "Growth Partners"], + "startup": ["Innovation Labs", "Future Works", "Venture Co", "Next Gen"] + }, + + "projectSuggestions": { + "freelancer": ["Kundenprojekt", "Portfolio-Update", "Persönliche Marke"], + "startup": ["MVP-Entwicklung", "Produktlaunch", "Marktforschung"], + "agency": ["Kundenkampagne", "Markenstrategie", "Website-Redesign"], + "enterprise": ["Systemumstellung", "Prozessoptimierung", "Teamschulung"] + }, + + "useCaseDescriptions": { + "taskManagement": "Aufgaben organisieren und verfolgen", + "teamCollaboration": "Nahtlos zusammenarbeiten", + "resourcePlanning": "Zeit und Ressourcen verwalten", + "clientCommunication": "Mit Kunden in Verbindung bleiben", + "timeTracking": "Projektstunden überwachen", + "other": "Etwas anderes" + } } diff --git a/worklenz-frontend/public/locales/de/admin-center/configuration.json b/worklenz-frontend/public/locales/de/admin-center/configuration.json new file mode 100644 index 00000000..79d33f27 --- /dev/null +++ b/worklenz-frontend/public/locales/de/admin-center/configuration.json @@ -0,0 +1,26 @@ +{ + "billingDetails": "Abrechnungsdetails", + "name": "Name", + "namePlaceholder": "Name", + "emailAddress": "E-Mail-Adresse", + "emailPlaceholder": "E-Mail-Adresse", + "contactNumber": "Telefonnummer", + "phoneNumberPlaceholder": "Telefonnummer", + "phoneValidationError": "Telefonnummer muss genau 10 Ziffern haben", + "companyDetails": "Firmendetails", + "companyName": "Firmenname", + "companyNamePlaceholder": "Firmenname", + "addressLine01": "Adresszeile 01", + "addressLine01Placeholder": "Adresszeile 01", + "addressLine02": "Adresszeile 02", + "addressLine02Placeholder": "Adresszeile 02", + "country": "Land", + "countryPlaceholder": "Land", + "city": "Stadt", + "cityPlaceholder": "Stadt", + "state": "Bundesland", + "statePlaceholder": "Bundesland", + "postalCode": "Postleitzahl", + "postalCodePlaceholder": "Postleitzahl", + "save": "Speichern" +} \ No newline at end of file diff --git a/worklenz-frontend/public/locales/en/account-setup.json b/worklenz-frontend/public/locales/en/account-setup.json index c566d20a..22681256 100644 --- a/worklenz-frontend/public/locales/en/account-setup.json +++ b/worklenz-frontend/public/locales/en/account-setup.json @@ -1,7 +1,7 @@ { "continue": "Continue", - "setupYourAccount": "Setup Your Worklenz Account.", + "setupYourAccount": "Setup Your Account.", "organizationStepTitle": "Name Your Organization", "organizationStepWelcome": "Welcome to Worklenz!", "organizationStepDescription": "Let's start by setting up your organization. This will be the main workspace for your team.", @@ -30,7 +30,6 @@ "projectStepLabel": "What project are you working on right now?", "projectStepPlaceholder": "e.g. Marketing Plan", - "tasksStepTitle": "Create your first tasks", "tasksStepLabel": "Type a few tasks that you are going to do in", "tasksStepAddAnother": "Add another", @@ -51,10 +50,10 @@ "maxTasks": " (You can create up to 5 tasks)", "membersStepTitle": "Invite your team", - "membersStepDescription": "Add team members to \"{organizationName}\" and start collaborating", - "memberPlaceholder": "Team member {index} - Enter email address", + "membersStepDescription": "Add team members to \"{{organizationName}}\" and start collaborating", + "memberPlaceholder": "Team member {{index}} - Enter email address", "validEmailAddress": "Valid email address", - "addAnotherTeamMember": "Add another team member ({current}/{max})", + "addAnotherTeamMember": "Add another team member ({{current}}/{{max}})", "canInviteLater": "You can always invite team members later", "skipStepDescription": "Don't have email addresses ready? No problem! You can skip this step and invite team members from your project dashboard later.", @@ -83,7 +82,6 @@ "useCaseOther": "Something else", "selectedText": "selected", "previousToolsQuestion": "What tools have you used before? (Optional)", - "previousToolsPlaceholder": "e.g., Asana, Trello, Jira, Monday.com, etc.", "discoveryTitle": "One last thing...", "discoveryDescription": "Help us understand how you discovered Worklenz", @@ -119,9 +117,9 @@ "templateStartupDesc": "MVP development, funding, growth", "tasksStepTitle": "Add your first tasks", - "tasksStepDescription": "Break down \"{projectName}\" into actionable tasks to get started", - "taskPlaceholder": "Task {index} - e.g., What needs to be done?", - "addAnotherTask": "Add another task ({current}/{max})", + "tasksStepDescription": "Break down \"{{projectName}}\" into actionable tasks to get started", + "taskPlaceholder": "Task {{index}} - e.g., What needs to be done?", + "addAnotherTask": "Add another task ({{current}}/{{max}})", "surveyStepTitle": "Tell us about yourself", "surveyStepLabel": "Help us personalize your Worklenz experience by answering a few questions.", @@ -159,5 +157,53 @@ "howHeardAboutLinkedin": "LinkedIn", "howHeardAboutFriendColleague": "A friend or colleague", "howHeardAboutBlogArticle": "A blog or article", - "howHeardAboutOther": "Other" + "howHeardAboutOther": "Other", + + "aboutYouStepTitle": "Tell us about yourself", + "aboutYouStepDescription": "Help us personalize your experience", + "yourNeedsStepTitle": "What are your main needs?", + "yourNeedsStepDescription": "Select all that apply to help us set up your workspace", + "selected": "selected", + "previousToolsLabel": "What tools have you used before? (Optional)", + + "roleSuggestions": { + "designer": "UI/UX, Graphics, Creative", + "developer": "Frontend, Backend, Full-stack", + "projectManager": "Planning, Coordination", + "marketing": "Content, Social Media, Growth", + "sales": "Business Development, Client Relations", + "operations": "Admin, HR, Finance" + }, + + "languages": { + "en": "English", + "es": "Español", + "pt": "Português", + "de": "Deutsch", + "alb": "Shqip", + "zh": "简体中文" + }, + + "orgSuggestions": { + "tech": ["TechCorp", "DevStudio", "CodeCraft", "PixelForge"], + "creative": ["Creative Hub", "Design Studio", "Brand Works", "Visual Arts"], + "consulting": ["Strategy Group", "Business Solutions", "Expert Advisors", "Growth Partners"], + "startup": ["Innovation Labs", "Future Works", "Venture Co", "Next Gen"] + }, + + "projectSuggestions": { + "freelancer": ["Client Project", "Portfolio Update", "Personal Brand"], + "startup": ["MVP Development", "Product Launch", "Market Research"], + "agency": ["Client Campaign", "Brand Strategy", "Website Redesign"], + "enterprise": ["System Migration", "Process Optimization", "Team Training"] + }, + + "useCaseDescriptions": { + "taskManagement": "Organize and track tasks", + "teamCollaboration": "Work together seamlessly", + "resourcePlanning": "Manage time and resources", + "clientCommunication": "Stay connected with clients", + "timeTracking": "Monitor project hours", + "other": "Something else" + } } diff --git a/worklenz-frontend/public/locales/en/admin-center/configuration.json b/worklenz-frontend/public/locales/en/admin-center/configuration.json new file mode 100644 index 00000000..78293239 --- /dev/null +++ b/worklenz-frontend/public/locales/en/admin-center/configuration.json @@ -0,0 +1,26 @@ +{ + "billingDetails": "Billing Details", + "name": "Name", + "namePlaceholder": "Name", + "emailAddress": "Email Address", + "emailPlaceholder": "Email Address", + "contactNumber": "Contact Number", + "phoneNumberPlaceholder": "Phone Number", + "phoneValidationError": "Phone number must be exactly 10 digits", + "companyDetails": "Company Details", + "companyName": "Company Name", + "companyNamePlaceholder": "Company Name", + "addressLine01": "Address Line 01", + "addressLine01Placeholder": "Address Line 01", + "addressLine02": "Address Line 02", + "addressLine02Placeholder": "Address Line 02", + "country": "Country", + "countryPlaceholder": "Country", + "city": "City", + "cityPlaceholder": "City", + "state": "State", + "statePlaceholder": "State", + "postalCode": "Postal Code", + "postalCodePlaceholder": "Postal Code", + "save": "Save" +} \ No newline at end of file diff --git a/worklenz-frontend/public/locales/en/admin-center/current-bill.json b/worklenz-frontend/public/locales/en/admin-center/current-bill.json index fe840789..9ff09401 100644 --- a/worklenz-frontend/public/locales/en/admin-center/current-bill.json +++ b/worklenz-frontend/public/locales/en/admin-center/current-bill.json @@ -117,5 +117,26 @@ "currentSeatsText": "You currently have {{seats}} seats available.", "selectSeatsText": "Please select the number of additional seats to purchase.", "purchase": "Purchase", - "contactSales": "Contact sales" + "contactSales": "Contact sales", + "submitSuccess": "Code redeemed successfully!", + "submitSuccessDescription": "Your account has been updated with the new credits.", + "percentUsed": "% Used", + "sizeUnits": { + "bytes": "Bytes", + "kb": "KB", + "mb": "MB", + "gb": "GB", + "tb": "TB" + }, + "seatPerMonth": "seat / month", + "totalPrice": "Total $", + "tryForFree": "Try for free", + "subscriptionUpdateSuccess": "Subscription updated successfully!", + "paymentProcessorError": "Failed to load payment processor", + "seatsLabel": "Seats:", + "requiredField": "*", + "purchaseSeatsTextSingle": "To continue, you'll need to purchase an additional seat.", + "singleUserNote": "You currently have 1 seat available.", + "selectSeatsTextSingle": "Please select the number of additional seats to purchase.", + "phoneNumberPattern": "07xxxxxxxx" } diff --git a/worklenz-frontend/public/locales/en/admin-center/overview.json b/worklenz-frontend/public/locales/en/admin-center/overview.json index efc42855..3ec4329b 100644 --- a/worklenz-frontend/public/locales/en/admin-center/overview.json +++ b/worklenz-frontend/public/locales/en/admin-center/overview.json @@ -4,5 +4,8 @@ "owner": "Organization Owner", "admins": "Organization Admins", "contactNumber": "Add Contact Number", - "edit": "Edit" + "edit": "Edit", + "emailAddress": "Email Address", + "enterOrganizationName": "Enter organization name", + "ownerSuffix": " (Owner)" } diff --git a/worklenz-frontend/public/locales/en/admin-center/users.json b/worklenz-frontend/public/locales/en/admin-center/users.json index 7e462ef6..db2641a4 100644 --- a/worklenz-frontend/public/locales/en/admin-center/users.json +++ b/worklenz-frontend/public/locales/en/admin-center/users.json @@ -5,5 +5,6 @@ "user": "User", "email": "Email", "lastActivity": "Last Activity", - "refresh": "Refresh users" + "refresh": "Refresh users", + "name": "Name" } diff --git a/worklenz-frontend/public/locales/es/account-setup.json b/worklenz-frontend/public/locales/es/account-setup.json index 28092485..0910f64c 100644 --- a/worklenz-frontend/public/locales/es/account-setup.json +++ b/worklenz-frontend/public/locales/es/account-setup.json @@ -52,10 +52,10 @@ "maxTasks": " (Puedes crear hasta 5 tareas)", "membersStepTitle": "Invita a tu equipo", - "membersStepDescription": "Añade miembros del equipo a \"{organizationName}\" y comienza a colaborar", - "memberPlaceholder": "Miembro del equipo {index} - Ingresa dirección de correo", + "membersStepDescription": "Añade miembros del equipo a \"{{organizationName}}\" y comienza a colaborar", + "memberPlaceholder": "Miembro del equipo {{index}} - Ingresa dirección de correo", "validEmailAddress": "Dirección de correo válida", - "addAnotherTeamMember": "Añadir otro miembro del equipo ({current}/{max})", + "addAnotherTeamMember": "Añadir otro miembro del equipo ({{current}}/{{max}})", "canInviteLater": "Siempre puedes invitar miembros del equipo más tarde", "skipStepDescription": "¿No tienes direcciones de correo listas? ¡No hay problema! Puedes omitir este paso e invitar miembros del equipo desde tu panel de proyecto más tarde.", @@ -120,9 +120,9 @@ "templateStartupDesc": "Desarrollo MVP, financiación, crecimiento", "tasksStepTitle": "Añade tus primeras tareas", - "tasksStepDescription": "Desglosa \"{projectName}\" en tareas accionables para comenzar", - "taskPlaceholder": "Tarea {index} - ej., ¿Qué necesita hacerse?", - "addAnotherTask": "Añadir otra tarea ({current}/{max})", + "tasksStepDescription": "Desglosa \"{{projectName}}\" en tareas accionables para comenzar", + "taskPlaceholder": "Tarea {{index}} - ej., ¿Qué necesita hacerse?", + "addAnotherTask": "Añadir otra tarea ({{current}}/{{max}})", "surveyStepTitle": "Cuéntanos sobre ti", "surveyStepLabel": "Ayúdanos a personalizar tu experiencia de Worklenz respondiendo algunas preguntas.", @@ -160,5 +160,53 @@ "howHeardAboutLinkedin": "LinkedIn", "howHeardAboutFriendColleague": "Un amigo o colega", "howHeardAboutBlogArticle": "Un blog o artículo", - "howHeardAboutOther": "Otro" + "howHeardAboutOther": "Otro", + + "aboutYouStepTitle": "Cuéntanos sobre ti", + "aboutYouStepDescription": "Ayúdanos a personalizar tu experiencia", + "yourNeedsStepTitle": "¿Cuáles son tus principales necesidades?", + "yourNeedsStepDescription": "Selecciona todas las que apliquen para ayudarnos a configurar tu espacio de trabajo", + "selected": "seleccionado", + "previousToolsLabel": "¿Qué herramientas has usado antes? (Opcional)", + + "roleSuggestions": { + "designer": "UI/UX, Gráficos, Creativo", + "developer": "Frontend, Backend, Full-stack", + "projectManager": "Planificación, Coordinación", + "marketing": "Contenido, Redes Sociales, Crecimiento", + "sales": "Desarrollo de Negocios, Relaciones con Clientes", + "operations": "Administración, RRHH, Finanzas" + }, + + "languages": { + "en": "English", + "es": "Español", + "pt": "Português", + "de": "Deutsch", + "alb": "Shqip", + "zh": "简体中文" + }, + + "orgSuggestions": { + "tech": ["TechCorp", "DevStudio", "CodeCraft", "PixelForge"], + "creative": ["Creative Hub", "Design Studio", "Brand Works", "Visual Arts"], + "consulting": ["Strategy Group", "Business Solutions", "Expert Advisors", "Growth Partners"], + "startup": ["Innovation Labs", "Future Works", "Venture Co", "Next Gen"] + }, + + "projectSuggestions": { + "freelancer": ["Proyecto Cliente", "Actualización Portfolio", "Marca Personal"], + "startup": ["Desarrollo MVP", "Lanzamiento Producto", "Investigación Mercado"], + "agency": ["Campaña Cliente", "Estrategia Marca", "Rediseño Website"], + "enterprise": ["Migración Sistema", "Optimización Procesos", "Capacitación Equipo"] + }, + + "useCaseDescriptions": { + "taskManagement": "Organizar y rastrear tareas", + "teamCollaboration": "Trabajar juntos sin problemas", + "resourcePlanning": "Gestionar tiempo y recursos", + "clientCommunication": "Mantenerse conectado con clientes", + "timeTracking": "Monitorear horas de proyecto", + "other": "Algo más" + } } diff --git a/worklenz-frontend/public/locales/pt/account-setup.json b/worklenz-frontend/public/locales/pt/account-setup.json index abbd6500..68cdd224 100644 --- a/worklenz-frontend/public/locales/pt/account-setup.json +++ b/worklenz-frontend/public/locales/pt/account-setup.json @@ -52,10 +52,10 @@ "maxTasks": " (Você pode criar até 5 tarefas)", "membersStepTitle": "Convide sua equipe", - "membersStepDescription": "Adicione membros da equipe ao \"{organizationName}\" e comece a colaborar", - "memberPlaceholder": "Membro da equipe {index} - Digite o endereço de email", + "membersStepDescription": "Adicione membros da equipe ao \"{{organizationName}}\" e comece a colaborar", + "memberPlaceholder": "Membro da equipe {{index}} - Digite o endereço de email", "validEmailAddress": "Endereço de email válido", - "addAnotherTeamMember": "Adicionar outro membro da equipe ({current}/{max})", + "addAnotherTeamMember": "Adicionar outro membro da equipe ({{current}}/{{max}})", "canInviteLater": "Você sempre pode convidar membros da equipe mais tarde", "skipStepDescription": "Não tem endereços de email prontos? Sem problema! Você pode pular esta etapa e convidar membros da equipe do seu painel de projeto mais tarde.", @@ -120,9 +120,9 @@ "templateStartupDesc": "Desenvolvimento MVP, financiamento, crescimento", "tasksStepTitle": "Adicione suas primeiras tarefas", - "tasksStepDescription": "Divida \"{projectName}\" em tarefas acionáveis para começar", - "taskPlaceholder": "Tarefa {index} - ex., O que precisa ser feito?", - "addAnotherTask": "Adicionar outra tarefa ({current}/{max})", + "tasksStepDescription": "Divida \"{{projectName}}\" em tarefas acionáveis para começar", + "taskPlaceholder": "Tarefa {{index}} - ex., O que precisa ser feito?", + "addAnotherTask": "Adicionar outra tarefa ({{current}}/{{max}})", "surveyStepTitle": "Conte-nos sobre você", "surveyStepLabel": "Ajude-nos a personalizar sua experiência no Worklenz respondendo algumas perguntas.", @@ -160,5 +160,53 @@ "howHeardAboutLinkedin": "LinkedIn", "howHeardAboutFriendColleague": "Um amigo ou colega", "howHeardAboutBlogArticle": "Um blog ou artigo", - "howHeardAboutOther": "Outro" + "howHeardAboutOther": "Outro", + + "aboutYouStepTitle": "Conte-nos sobre você", + "aboutYouStepDescription": "Ajude-nos a personalizar sua experiência", + "yourNeedsStepTitle": "Quais são suas principais necessidades?", + "yourNeedsStepDescription": "Selecione todas que se aplicam para nos ajudar a configurar seu espaço de trabalho", + "selected": "selecionado", + "previousToolsLabel": "Que ferramentas você usou antes? (Opcional)", + + "roleSuggestions": { + "designer": "UI/UX, Gráficos, Criativo", + "developer": "Frontend, Backend, Full-stack", + "projectManager": "Planejamento, Coordenação", + "marketing": "Conteúdo, Mídias Sociais, Crescimento", + "sales": "Desenvolvimento de Negócios, Relacionamento com Clientes", + "operations": "Administração, RH, Finanças" + }, + + "languages": { + "en": "English", + "es": "Español", + "pt": "Português", + "de": "Deutsch", + "alb": "Shqip", + "zh": "简体中文" + }, + + "orgSuggestions": { + "tech": ["TechCorp", "DevStudio", "CodeCraft", "PixelForge"], + "creative": ["Creative Hub", "Design Studio", "Brand Works", "Visual Arts"], + "consulting": ["Strategy Group", "Business Solutions", "Expert Advisors", "Growth Partners"], + "startup": ["Innovation Labs", "Future Works", "Venture Co", "Next Gen"] + }, + + "projectSuggestions": { + "freelancer": ["Projeto Cliente", "Atualização Portfolio", "Marca Pessoal"], + "startup": ["Desenvolvimento MVP", "Lançamento Produto", "Pesquisa Mercado"], + "agency": ["Campanha Cliente", "Estratégia Marca", "Redesign Website"], + "enterprise": ["Migração Sistema", "Otimização Processos", "Treinamento Equipe"] + }, + + "useCaseDescriptions": { + "taskManagement": "Organizar e rastrear tarefas", + "teamCollaboration": "Trabalhar juntos perfeitamente", + "resourcePlanning": "Gerenciar tempo e recursos", + "clientCommunication": "Manter-se conectado com clientes", + "timeTracking": "Monitorar horas do projeto", + "other": "Algo mais" + } } diff --git a/worklenz-frontend/public/locales/zh/account-setup.json b/worklenz-frontend/public/locales/zh/account-setup.json index 86599fd2..57b8aa25 100644 --- a/worklenz-frontend/public/locales/zh/account-setup.json +++ b/worklenz-frontend/public/locales/zh/account-setup.json @@ -50,10 +50,10 @@ "maxTasks": "(您最多可以创建 5 个任务)", "membersStepTitle": "邀请您的团队", - "membersStepDescription": "将团队成员添加到 \"{organizationName}\" 并开始协作", - "memberPlaceholder": "团队成员 {index} - 输入电子邮件地址", + "membersStepDescription": "将团队成员添加到 \"{{organizationName}}\" 并开始协作", + "memberPlaceholder": "团队成员 {{index}} - 输入电子邮件地址", "validEmailAddress": "有效的电子邮件地址", - "addAnotherTeamMember": "添加另一个团队成员 ({current}/{max})", + "addAnotherTeamMember": "添加另一个团队成员 ({{current}}/{{max}})", "canInviteLater": "您可以稍后邀请团队成员", "skipStepDescription": "没有准备好电子邮件地址?没关系!您可以跳过此步骤,稍后从项目面板邀请团队成员。", @@ -118,9 +118,9 @@ "templateStartupDesc": "MVP 开发、融资、增长", "tasksStepTitle": "添加您的第一个任务", - "tasksStepDescription": "将 \"{projectName}\" 拆分为可执行任务以开始", - "taskPlaceholder": "任务 {index} - 例如:需要做什么?", - "addAnotherTask": "添加另一个任务 ({current}/{max})", + "tasksStepDescription": "将 \"{{projectName}}\" 拆分为可执行任务以开始", + "taskPlaceholder": "任务 {{index}} - 例如:需要做什么?", + "addAnotherTask": "添加另一个任务 ({{current}}/{{max}})", "surveyStepTitle": "告诉我们关于您的信息", "surveyStepLabel": "通过回答几个问题帮助我们个性化您的 Worklenz 体验。", @@ -158,5 +158,53 @@ "howHeardAboutLinkedin": "LinkedIn", "howHeardAboutFriendColleague": "朋友或同事", "howHeardAboutBlogArticle": "博客或文章", - "howHeardAboutOther": "其他" + "howHeardAboutOther": "其他", + + "aboutYouStepTitle": "告诉我们关于您的信息", + "aboutYouStepDescription": "帮助我们个性化您的体验", + "yourNeedsStepTitle": "您的主要需求是什么?", + "yourNeedsStepDescription": "选择所有适用的选项,帮助我们设置您的工作空间", + "selected": "已选择", + "previousToolsLabel": "您之前使用过哪些工具?(可选)", + + "roleSuggestions": { + "designer": "UI/UX、图形、创意", + "developer": "前端、后端、全栈", + "projectManager": "规划、协调", + "marketing": "内容、社交媒体、增长", + "sales": "业务发展、客户关系", + "operations": "行政、人力资源、财务" + }, + + "languages": { + "en": "English", + "es": "Español", + "pt": "Português", + "de": "Deutsch", + "alb": "Shqip", + "zh": "简体中文" + }, + + "orgSuggestions": { + "tech": ["TechCorp", "DevStudio", "CodeCraft", "PixelForge"], + "creative": ["Creative Hub", "Design Studio", "Brand Works", "Visual Arts"], + "consulting": ["Strategy Group", "Business Solutions", "Expert Advisors", "Growth Partners"], + "startup": ["Innovation Labs", "Future Works", "Venture Co", "Next Gen"] + }, + + "projectSuggestions": { + "freelancer": ["客户项目", "作品集更新", "个人品牌"], + "startup": ["MVP开发", "产品发布", "市场调研"], + "agency": ["客户活动", "品牌策略", "网站重设计"], + "enterprise": ["系统迁移", "流程优化", "团队培训"] + }, + + "useCaseDescriptions": { + "taskManagement": "组织和跟踪任务", + "teamCollaboration": "无缝协作", + "resourcePlanning": "管理时间和资源", + "clientCommunication": "与客户保持联系", + "timeTracking": "监控项目时间", + "other": "其他" + } } diff --git a/worklenz-frontend/src/components/account-setup/admin-center-common.css b/worklenz-frontend/src/components/account-setup/admin-center-common.css deleted file mode 100644 index f4c9c421..00000000 --- a/worklenz-frontend/src/components/account-setup/admin-center-common.css +++ /dev/null @@ -1,19 +0,0 @@ -@media (max-width: 1000px) { - .step-content, - .step-form, - .create-first-task-form, - .setup-action-buttons, - .invite-members-form { - width: 400px !important; - } -} - -@media (max-width: 500px) { - .step-content, - .step-form, - .create-first-task-form, - .setup-action-buttons, - .invite-members-form { - width: 200px !important; - } -} diff --git a/worklenz-frontend/src/components/account-setup/members-step.tsx b/worklenz-frontend/src/components/account-setup/members-step.tsx index 7fe12da5..a9759f33 100644 --- a/worklenz-frontend/src/components/account-setup/members-step.tsx +++ b/worklenz-frontend/src/components/account-setup/members-step.tsx @@ -22,29 +22,19 @@ interface MembersStepProps { token?: any; } -// Common email suggestions based on organization const getEmailSuggestions = (orgName?: string) => { if (!orgName) return []; - const cleanOrgName = orgName.toLowerCase().replace(/[^a-z0-9]/g, ''); - const suggestions = [ - `info@${cleanOrgName}.com`, - `team@${cleanOrgName}.com`, - `hello@${cleanOrgName}.com`, - `contact@${cleanOrgName}.com` - ]; - - return suggestions; + return [`info@${cleanOrgName}.com`, `team@${cleanOrgName}.com`, `hello@${cleanOrgName}.com`, `contact@${cleanOrgName}.com`]; }; -// Role suggestions for team members -const roleSuggestions = [ - { role: 'Designer', icon: '🎨', description: 'UI/UX, Graphics, Creative' }, - { role: 'Developer', icon: '💻', description: 'Frontend, Backend, Full-stack' }, - { role: 'Project Manager', icon: '📊', description: 'Planning, Coordination' }, - { role: 'Marketing', icon: '📢', description: 'Content, Social Media, Growth' }, - { role: 'Sales', icon: '💼', description: 'Business Development, Client Relations' }, - { role: 'Operations', icon: '⚙️', description: 'Admin, HR, Finance' } +const getRoleSuggestions = (t: any) => [ + { role: 'Designer', icon: '🎨', description: t('roleSuggestions.designer') }, + { role: 'Developer', icon: '💻', description: t('roleSuggestions.developer') }, + { role: 'Project Manager', icon: '📊', description: t('roleSuggestions.projectManager') }, + { role: 'Marketing', icon: '📢', description: t('roleSuggestions.marketing') }, + { role: 'Sales', icon: '💼', description: t('roleSuggestions.sales') }, + { role: 'Operations', icon: '⚙️', description: t('roleSuggestions.operations') } ]; const MembersStep: React.FC = ({ isDarkMode, styles, token }) => { @@ -63,30 +53,18 @@ const MembersStep: React.FC = ({ isDarkMode, styles, token }) const addEmail = () => { if (teamMembers.length >= 5) return; - const newId = teamMembers.length > 0 ? Math.max(...teamMembers.map(t => t.id)) + 1 : 0; dispatch(setTeamMembers([...teamMembers, { id: newId, value: '' }])); - setTimeout(() => { - const newIndex = teamMembers.length; - inputRefs.current[newIndex]?.focus(); - }, 100); + setTimeout(() => inputRefs.current[teamMembers.length]?.focus(), 100); }; const removeEmail = (id: number) => { - if (teamMembers.length > 1) { - dispatch(setTeamMembers(teamMembers.filter(teamMember => teamMember.id !== id))); - } + if (teamMembers.length > 1) dispatch(setTeamMembers(teamMembers.filter(teamMember => teamMember.id !== id))); }; const updateEmail = (id: number, value: string) => { const sanitizedValue = sanitizeInput(value); - dispatch( - setTeamMembers( - teamMembers.map(teamMember => - teamMember.id === id ? { ...teamMember, value: sanitizedValue } : teamMember - ) - ) - ); + dispatch(setTeamMembers(teamMembers.map(teamMember => teamMember.id === id ? { ...teamMember, value: sanitizedValue } : teamMember))); }; const handleKeyPress = (e: React.KeyboardEvent, index: number) => { @@ -94,11 +72,8 @@ const MembersStep: React.FC = ({ isDarkMode, styles, token }) const input = e.currentTarget as HTMLInputElement; if (input.value.trim() && validateEmail(input.value.trim())) { e.preventDefault(); - if (index === teamMembers.length - 1 && teamMembers.length < 5) { - addEmail(); - } else if (index < teamMembers.length - 1) { - inputRefs.current[index + 1]?.focus(); - } + if (index === teamMembers.length - 1 && teamMembers.length < 5) addEmail(); + else if (index < teamMembers.length - 1) inputRefs.current[index + 1]?.focus(); } } }; @@ -115,32 +90,27 @@ const MembersStep: React.FC = ({ isDarkMode, styles, token }) }; useEffect(() => { - setTimeout(() => { - inputRefs.current[0]?.focus(); - }, 200); + setTimeout(() => inputRefs.current[0]?.focus(), 200); }, []); const getEmailStatus = (email: string, memberId: number) => { if (!email.trim()) return 'empty'; if (!validatedEmails.has(memberId)) return 'empty'; - if (validateEmail(email)) return 'valid'; - return 'invalid'; + return validateEmail(email) ? 'valid' : 'invalid'; }; const handleBlur = (memberId: number, email: string) => { setFocusedIndex(null); - if (email.trim()) { - setValidatedEmails(prev => new Set(prev).add(memberId)); - } + if (email.trim()) setValidatedEmails(prev => new Set(prev).add(memberId)); }; const languages = [ - { key: 'en', label: 'English', flag: '🇺🇸' }, - { key: 'es', label: 'Español', flag: '🇪🇸' }, - { key: 'pt', label: 'Português', flag: '🇵🇹' }, - { key: 'de', label: 'Deutsch', flag: '🇩🇪' }, - { key: 'alb', label: 'Shqip', flag: '🇦🇱' }, - { key: 'zh', label: '简体中文', flag: '🇨🇳' } + { key: 'en', label: t('languages.en'), flag: '🇺🇸' }, + { key: 'es', label: t('languages.es'), flag: '🇪🇸' }, + { key: 'pt', label: t('languages.pt'), flag: '🇵🇹' }, + { key: 'de', label: t('languages.de'), flag: '🇩🇪' }, + { key: 'alb', label: t('languages.alb'), flag: '🇦🇱' }, + { key: 'zh', label: t('languages.zh'), flag: '🇨🇳' } ]; const handleLanguageChange = (languageKey: string) => { @@ -148,18 +118,8 @@ const MembersStep: React.FC = ({ isDarkMode, styles, token }) i18n.changeLanguage(languageKey); }; - const languageMenuItems: MenuProps['items'] = languages.map(lang => ({ - key: lang.key, - label: ( -
- {lang.flag} - {lang.label} -
- ), - onClick: () => handleLanguageChange(lang.key) - })); - const currentLanguage = languages.find(lang => lang.key === language) || languages[0]; + const languageMenuItems: MenuProps['items'] = languages.map(lang => ({ key: lang.key, label:
{lang.flag}{lang.label}
, onClick: () => handleLanguageChange(lang.key) })); return (
@@ -284,26 +244,6 @@ const MembersStep: React.FC = ({ isDarkMode, styles, token }) }} />
- - {/* Language Switcher */} -
- - - -
); }; diff --git a/worklenz-frontend/src/components/account-setup/organization-step.tsx b/worklenz-frontend/src/components/account-setup/organization-step.tsx index 2663e64c..87e4ab9a 100644 --- a/worklenz-frontend/src/components/account-setup/organization-step.tsx +++ b/worklenz-frontend/src/components/account-setup/organization-step.tsx @@ -1,11 +1,10 @@ import React, { useEffect, useRef, useState } from 'react'; -import { Form, Input, InputRef, Typography, Card, Row, Col, Tag, Tooltip, Button } from '@/shared/antd-imports'; +import { Form, Input, InputRef, Typography, Card, Tooltip } from '@/shared/antd-imports'; import { useDispatch, useSelector } from 'react-redux'; import { useTranslation } from 'react-i18next'; import { setOrganizationName } from '@/features/account-setup/account-setup.slice'; import { RootState } from '@/app/store'; import { sanitizeInput } from '@/utils/sanitizeInput'; -import './admin-center-common.css'; const { Title, Paragraph, Text } = Typography; @@ -18,15 +17,6 @@ interface Props { token?: any; } -// Organization name suggestions by type -const organizationSuggestions = [ - { category: 'Tech Companies', examples: ['TechCorp', 'DevStudio', 'CodeCraft', 'PixelForge'] }, - { category: 'Creative Agencies', examples: ['Creative Hub', 'Design Studio', 'Brand Works', 'Visual Arts'] }, - { category: 'Consulting', examples: ['Strategy Group', 'Business Solutions', 'Expert Advisors', 'Growth Partners'] }, - { category: 'Startups', examples: ['Innovation Labs', 'Future Works', 'Venture Co', 'Next Gen'] }, -]; - - export const OrganizationStep: React.FC = ({ onEnter, styles, @@ -39,8 +29,6 @@ export const OrganizationStep: React.FC = ({ const dispatch = useDispatch(); const { organizationName } = useSelector((state: RootState) => state.accountSetupReducer); const inputRef = useRef(null); - const [showSuggestions, setShowSuggestions] = useState(false); - const [selectedCategory, setSelectedCategory] = useState(null); // Autofill organization name if not already set useEffect(() => { @@ -60,16 +48,6 @@ export const OrganizationStep: React.FC = ({ dispatch(setOrganizationName(sanitizedValue)); }; - const handleSuggestionClick = (suggestion: string) => { - dispatch(setOrganizationName(suggestion)); - inputRef.current?.focus(); - setShowSuggestions(false); - }; - - const toggleSuggestions = () => { - setShowSuggestions(!showSuggestions); - }; - return (
{/* Header */} @@ -110,43 +88,15 @@ export const OrganizationStep: React.FC = ({ } > - {/* Quick Actions */} -
- - {organizationNameInitialValue && organizationNameInitialValue !== organizationName && ( - - )} -
- {/* Character Count and Validation */}
@@ -165,62 +115,6 @@ export const OrganizationStep: React.FC = ({
- - {/* Suggestions Panel */} - {showSuggestions && ( -
- - 🎯 - {t('organizationStepSuggestionsTitle')} -
- } - style={{ backgroundColor: token?.colorBgContainer }} - > -
- {organizationSuggestions.map((category, categoryIndex) => ( -
-
- setSelectedCategory( - selectedCategory === category.category ? null : category.category - )} - > - {t(`organizationStepCategory${categoryIndex + 1}`, category.category)} - -
-
- {category.examples.map((example, exampleIndex) => ( - - ))} -
-
- ))} -
- -
- - 💡 {t('organizationStepSuggestionsNote')} - -
- -
- )} - {/* Footer Note */}
{ + if (!name) return '📁'; + const lowercaseName = name.toLowerCase(); + if (lowercaseName.includes('software') || lowercaseName.includes('development')) return '💻'; + if (lowercaseName.includes('marketing') || lowercaseName.includes('campaign')) return '📢'; + if (lowercaseName.includes('construction') || lowercaseName.includes('building')) return '🏗️'; + if (lowercaseName.includes('startup') || lowercaseName.includes('launch')) return '🚀'; + if (lowercaseName.includes('design') || lowercaseName.includes('creative')) return '🎨'; + if (lowercaseName.includes('education') || lowercaseName.includes('learning')) return '📚'; + if (lowercaseName.includes('event') || lowercaseName.includes('planning')) return '📅'; + if (lowercaseName.includes('retail') || lowercaseName.includes('sales')) return '🛍️'; + return '📁'; +}; -// Project name suggestions based on organization type const getProjectSuggestions = (orgType?: string) => { const suggestions: Record = { 'freelancer': ['Client Website', 'Logo Design', 'Content Writing', 'App Development'], @@ -75,7 +57,6 @@ const getProjectSuggestions = (orgType?: string) => { 'enterprise': ['Digital Transformation', 'System Migration', 'Annual Planning', 'Department Initiative'], 'other': ['New Project', 'Team Initiative', 'Q1 Goals', 'Special Project'] }; - return suggestions[orgType || 'other'] || suggestions['other']; }; @@ -89,8 +70,46 @@ export const ProjectStep: React.FC = ({ onEnter, styles, isDarkMode = fal useEffect(() => { setTimeout(() => inputRef.current?.focus(), 200); + fetchTemplates(); }, []); + const fetchTemplates = async () => { + try { + setLoadingTemplates(true); + setTemplateError(null); + + // Fetch list of available templates + const templatesResponse = await projectTemplatesApiService.getWorklenzTemplates(); + + if (templatesResponse.done && templatesResponse.body) { + // Fetch detailed information for first 4 templates for preview + const templateDetails = await Promise.all( + templatesResponse.body.slice(0, 4).map(async (template) => { + if (template.id) { + try { + const detailResponse = await projectTemplatesApiService.getByTemplateId(template.id); + return detailResponse.done ? detailResponse.body : null; + } catch (error) { + logger.error(`Failed to fetch template details for ${template.id}`, error); + return null; + } + } + return null; + }) + ); + + // Filter out null results and set templates + const validTemplates = templateDetails.filter((template): template is IProjectTemplate => template !== null); + setTemplates(validTemplates); + } + } catch (error) { + logger.error('Failed to fetch templates', error); + setTemplateError('Failed to load templates'); + } finally { + setLoadingTemplates(false); + } + }; + const { projectName, templateId, organizationName, surveyData } = useSelector( (state: RootState) => state.accountSetupReducer @@ -98,6 +117,9 @@ export const ProjectStep: React.FC = ({ onEnter, styles, isDarkMode = fal const [open, setOpen] = useState(false); const [creatingFromTemplate, setCreatingFromTemplate] = useState(false); const [selectedTemplate, setSelectedTemplate] = useState(templateId || null); + const [templates, setTemplates] = useState([]); + const [loadingTemplates, setLoadingTemplates] = useState(true); + const [templateError, setTemplateError] = useState(null); const projectSuggestions = getProjectSuggestions(surveyData.organization_type); @@ -125,8 +147,6 @@ export const ProjectStep: React.FC = ({ onEnter, styles, isDarkMode = fal if (res.done && res.body.id) { toggleTemplateSelector(false); trackMixpanelEvent(evt_account_setup_template_complete); - - // Refresh user session to update setup_completed status try { const authResponse = await dispatch(verifyAuthentication()).unwrap() as IAuthorizeResponse; if (authResponse?.authenticated && authResponse?.user) { @@ -136,7 +156,6 @@ export const ProjectStep: React.FC = ({ onEnter, styles, isDarkMode = fal } catch (error) { logger.error('Failed to refresh user session after template setup completion', error); } - navigate(`/worklenz/projects/${res.body.id}?tab=tasks-list&pinned_tab=tasks-list`); } } catch (error) { @@ -145,8 +164,7 @@ export const ProjectStep: React.FC = ({ onEnter, styles, isDarkMode = fal }; const onPressEnter = () => { - if (!projectName.trim()) return; - onEnter(); + if (projectName.trim()) onEnter(); }; const handleProjectNameChange = (e: React.ChangeEvent) => { @@ -155,7 +173,6 @@ export const ProjectStep: React.FC = ({ onEnter, styles, isDarkMode = fal }; const handleProjectNameFocus = () => { - // Clear template selection when user focuses on project name input if (templateId) { dispatch(setTemplateId(null)); setSelectedTemplate(null); @@ -172,10 +189,10 @@ export const ProjectStep: React.FC = ({ onEnter, styles, isDarkMode = fal {/* Header */}
- Let's create your first project + {t('projectStepHeader')} - Start from scratch or use a template to get going faster + {t('projectStepSubheader')}
@@ -193,11 +210,11 @@ export const ProjectStep: React.FC = ({ onEnter, styles, isDarkMode = fal
- Start from scratch + {t('startFromScratch')} {templateId && ( - Template selected below + {t('templateSelected')} )}
@@ -216,31 +233,15 @@ export const ProjectStep: React.FC = ({ onEnter, styles, isDarkMode = fal onFocus={handleProjectNameFocus} ref={inputRef} className="text-base" - style={{ - backgroundColor: token?.colorBgContainer, - borderColor: token?.colorBorder, - color: token?.colorText - }} + style={{ backgroundColor: token?.colorBgContainer, borderColor: token?.colorBorder, color: token?.colorText }} /> - {/* Quick suggestions */}
- - Quick suggestions: - + {t('quickSuggestions')}
{projectSuggestions.map((suggestion, index) => ( - ))} @@ -249,103 +250,110 @@ export const ProjectStep: React.FC = ({ onEnter, styles, isDarkMode = fal
- {/* OR Divider */}
-
+
- - OR - + {t('orText')}
- {/* Template Section */}
- - Start with a template - + {t('startWithTemplate')} - {projectName?.trim() - ? "Clear project name above to select a template" - : "Get a head start with pre-built project structures" - } + {t('templateHeadStart')}
{/* Template Preview Cards */} - - {templateSuggestions.map((template) => ( - - { - if (projectName?.trim()) return; // Don't allow selection if project name is entered - setSelectedTemplate(template.id); - dispatch(setTemplateId(template.id)); - }} - > -
- {template.icon} -
- - {template.title} - - - {template.description} - -
- {template.tags.map((tag, index) => ( - - {tag} - - ))} +
+ {loadingTemplates ? ( +
+ +
+ Loading templates... +
+
+ ) : templateError ? ( + + Retry + + } + /> + ) : ( + + {templates.map((template) => ( + + { + setSelectedTemplate(template.id || null); + dispatch(setTemplateId(template.id || '')); + }} + > +
+ {template.image_url ? ( + {template.name} { + // Fallback to icon if image fails to load + e.currentTarget.style.display = 'none'; + if (e.currentTarget.nextSibling) { + (e.currentTarget.nextSibling as HTMLElement).style.display = 'block'; + } + }} + /> + ) : null} + + {getTemplateIcon(template.name)} + +
+ + {template.name || 'Untitled Template'} + +
+ {template.phases?.slice(0, 3).map((phase, index) => ( + + {phase.name} + + ))} + {(template.phases?.length || 0) > 3 && ( + +{(template.phases?.length || 0) - 3} more + )} +
+
-
-
- - - ))} - + + + ))} + + )} +
- {/* Browse All Templates Button */}
- +
- - 15+ industry-specific templates available - + {t('templatesAvailable')}
@@ -359,7 +367,7 @@ export const ProjectStep: React.FC = ({ onEnter, styles, isDarkMode = fal {t('templateDrawerTitle')} - Choose a template that matches your project type + {t('chooseTemplate')}
} @@ -377,7 +385,7 @@ export const ProjectStep: React.FC = ({ onEnter, styles, isDarkMode = fal loading={creatingFromTemplate} disabled={!templateId} > - {t('create')} Project +{t('createProject')}
} diff --git a/worklenz-frontend/src/components/account-setup/survey-step.tsx b/worklenz-frontend/src/components/account-setup/survey-step.tsx index 1e3dd3bd..2394ac06 100644 --- a/worklenz-frontend/src/components/account-setup/survey-step.tsx +++ b/worklenz-frontend/src/components/account-setup/survey-step.tsx @@ -57,42 +57,38 @@ const AboutYouPage: React.FC = ({ styles, token, surveyData, ha
- Tell us about yourself + {t('aboutYouStepTitle')} - Help us personalize your experience + {t('aboutYouStepDescription')}
{/* Organization Type */} -
+
{organizationTypeOptions.map((option) => { const isSelected = surveyData.organization_type === option.value; return ( ); @@ -244,7 +211,7 @@ const YourNeedsPage: React.FC = ({ styles, token, surveyData, h
{surveyData.main_use_cases && surveyData.main_use_cases.length > 0 && (

- {surveyData.main_use_cases.length} selected + {surveyData.main_use_cases.length} {t('selected')}

)} @@ -252,7 +219,7 @@ const YourNeedsPage: React.FC = ({ styles, token, surveyData, h {/* Previous Tools */}