Webbutvecklingsdagbok - efter studierna

Permalänk

Webbutvecklingsdagbok - efter studierna

Jobb & Uppdrag
Jag kan med glädjande besked att imorgon - fredagen den 6:e september 2024 - är den sista arbetsdagen för detta drygt åtta veckor uppdrag hos Uppdragsgivaren som tidigare var min exjobbsgivare. Hur kommer det sig då?

Först och främst så är jag i princip färdig med framsidan för den digitala modulen vilket är tänkt att fungera som marknadsföringsundersida. För det andra så är det som sagt var den sista arbetsdagen så ytterligare omfattande arbete skulle först kräva en ny offert att godkänna för att det skulle sättas i verk.

I och med ett lokalt jubileum här nere på staden så kommer jag att befinna mig på lokalkänd plats och samverka med Uppdragsgivaren inför deras presentation, demonstration och lansering av deras unika program vilket består av ett fysiskt brädspel som spelas ihop med den digitala modul jag har tagit fram åt Uppdragsgivaren i snart drygt åtta veckors tid.

Den digitala modulen har delvis varit en vidareutveckling på det exjobbsarbete jag gjorde åt numera Uppdragsgivaren under sista läsåret i Webbutvecklings-programmet 120hp på distans i kombination med en helt ny webbplats jag tog fram åt Uppdragsgivaren vilket utgör den så kallade digitala modulen i Uppdragsgivarens unika program de lanserar nu på fredag.

Jag undviker att namnge namn här eftersom det kan betraktas som marknadsföring men om du befinner dig i närheten av detta lokala jubileum och har vägarna förbi så kan du alltid besöka montern där jag kommer att befinna mig.

Jag kommer även att bidra med - hör och häpna - ljudutrustning åt Uppdragsgivaren så att de kan spela in bättre ljud än ljud från mikrofonen på en mobiltelefon som ska filma dem på flera meters avstånd.

Någon i någon Discordgrupp förvarnade mig då på, "Kommande inrapporterade buggar under en längre snar framtid!" efter denna skarpa lansering av den digitala modulen nu imorgon bitti!

Själva framsidan jag gjorde består av HTML5-kod, två stilmallar och massor av Tailwind-klasser inbakade i nästan alla HTML-element. Det finns en hamburgermeny som också inkluderar aria-attribut för de som vill navigera webbplatsen utan seende.

Det finns en hel del bilder så jag använde mig av gratiswebbtjänster för att först förminska dem i antalet pixlar (en bild var 8000x4000 så jag förminskade den ned till 4000x2000 då majoriteten av besökarna kommer att vara mobila men för den som vill nyttja 4K-skärm) och sedan komprimera filstorlekarna.

Jag fick sedan lära mig den hårda och petiga vägen att nyttja dynamiska bindestreck med hjälp av:­ vilket låter webbläsarna få avgöra om bindestreck behövs eller inte för att dela ord.

Något konstigt är/var att i FireFox-webbläsaren - senaste versionen - så bryts ett ord men i en annans samma FireFox-webbläsare och version så bryts inte ordet och då är ändå typsnitten samma. I Chrome och Edge för mig och samma person så bryts inte ordet ifråga.

Och frågan är ju hur mycket/länge en ska hålla på med att göra att själva textinnehållet ser estetiskt snyggt ut på så många skärmupplösningar som finns?🤔

Å ena sidan måste Uppdragsgivaren bestämma hur mycket prio det ska få och samtidigt så säger ju det estestiska också en del om mig som Uppdragstagare eftersom vissa besökare kan tolka det som om jag ligger 100 % bakom det estetiska trots att jag inte tagit fram några visuella prototyper.

Hursomhelst så är Uppdragsgivaren mycket nöjd än så länge med det jag gjort och nu när jag har gjort det sista(?) utifrån erhållna prototypfiler idag (JPG-bilder då InDesign-filerna var för stora att skicka) så tror jag att Uppdragsgivaren kommer att vara rätt så nöjd fortfarande.

Personligen är jag mycket nöjd med framsidan som faktiskt ser färgstarkt modernt ut, inger förtroende och en viss känsla tack vare dess "varma" färgval vilket är tack vare Uppdragsgivarens designer som tagit fram prototypfilerna åt mig!🫡

Efter fredagens presentation, demonstration och inspelade videoklipp så kommer även den att läggas upp. Jag funderar även på om jag ska återanvända en teknik som jag lärde mig från grafikkursen i distansutbildningen där jag använde ett loopat videoklipp som bakgrundsbild för att direkt fånga upp besökaren? Tål att diskuteras med Uppdragsgivaren. Så länge det finns en start-/stoppknapp så bör det vara en helt OK idé?🤔

I och med det snart första avklarade Uppdraget - och nu på fredag kan jag även skicka den tredje/sista fakturan - så funderar jag på att fixa konton hos Fiverr och UpWork för att börja bredda mig då jag kommer att behöva söka nya Uppdrag i väntan(?) på fler Uppdrag från samma nuvarande - och snart tidigare - Uppdragsgivare.

Hobbyprojekt
Inget nytt att rapportera.

Vidareutbildning
Inget nytt att rapportera mer än att jag har fått höra från en i släkten att Kubernetes verkar det saknas kompetens inom i IT-Sverige.

En i släkten som arbetar med servrar berättade att det är nästintill omöjligt att få tag på någon som är riktigt duktig på Kubernetes i Sverige då sådana personer oftast är mycket duktiga på annat också och dras från alla håll och kanter hos andra bolag där de redan arbetar.

Således funderar jag på att lära mig grundläggande Kubernetes. Aldrig fel att kunna än att inte kunna tänker jag.

Samtidigt inser jag att "om det vore så bara så borde ju flera ha redan lärt sig Kubernetes och fyllt den där kompetensluckan(?)!" Kanske det är detta med "Bra att du kan det men kan du inte ha jobbat fler år än du har existerat så vore det toppen?"-tänk från potentiella arbets-/uppdragsgivare?🤔

Vad anser Du om det här med att lära sig Kubernetes? Aldrig fel att kunna men högst osannolikt att bli "Uppdrags-uppraggad" efter det eftersom jag är ju knappast ensam om att försöka lära mig Kubernetes här i Sverige, eller hur?

På återseende!

(Vad passande att detta inlägg hamnade på andra sidan nästan som om ett nytt Uppdragskapitel snart börjar! )

Mvh,
WKF.
---------
✔️HT2022-VT2024 TWEUG Webbutvecklings-programmet 120hp (distans)

Visa signatur

(V)ulnerabilities
(I)n
(B)asically
(E)verything
Programming

Permalänk

Webbutvecklingsdagbok - efter studierna

Jobb & Uppdrag
I fredags så ägde presentationen rum nere på stan vid en gammal stenbyggnad där även självaste Sveriges nuvarande kung hade närvarat och käkat lunch. Jag träffade inte kungaparet dock.

Under presentationens gång runt cirka 11-snåret så hade jag tagit med mig ljudutrustning för att spela in bättre ljud. Jag bidrog med bättre ljud till en framtida presentation som kommer att läggas upp på deras numera lanserade webbplats.

En god vän till mig var med som är helt "färsk" och känner inte till bolagen som min Uppdragsgivare bedriver så för honom var det helt nytt och en del frågetecken.

Något Uppdragsgivaren ska göra härnäst är att marknadsföra sin produkt vilket är en kombination av ett fysiskt brädspel tillsammans med den framutvecklade digitala modulen jag har tagit fram de senaste åtta veckorna nu.

I fredags skickade jag även in den tredje och därmed sista fakturan då det hela delades in på tre delbetalningar under åtta veckors tid. Uppdragsgivaren berättade att de kommer att anlita mig vid framtida behov att vidareutveckla och/eller felsöka diverse saker i den digitala modulen i samband med att Uppdragsgivaren landar sin(a) första kund(er).

Syftet med Uppdragsgivarens produkt är att främja den psykiska hälsan hos arbetstagare ute på arbetsplatser vilket i sin tur ska bidra med att sänka kostnaderna hos arbetsgivaren genom färre sjukskrivningar och därmed förhoppningsvis lägre produktions-/personalbortfall.

Här gäller det då att marknadsföra sig korrekt: det är ledningsgrupper som ska pröjsa för det och de är då intresserade av de sistnämnda siffrorna medan kanske arbetstagarna, det vill säga "brukarna" eller "användarna" av det unika programmet högst troligt är intresserade av den psykologiska effekten.

Nästa steg för min egen del blir nu att söka nya Uppdrag i Sverige och utomlands (=Fiverr & UpWork). Detta steg sker i samverkan med att ta fram egna webbplatser för att profilera mig själv.

Utmaningen blir hur jag ska lägga upp mig själv, det vill säga hur jag ska "varumärkesföra" mig utifrån mina begränsade arbetserfarenheter som IT-frilanskonsult med inriktning webbutveckling.

Å ena sidan har jag genomfört ett kodprojekt med nöjda resultat (än så länge). Å andra sidan så har jag inte haft någon senior som har kunna gett mig "betygsättning" på hur 'avancerat' eller 'tekniskt imponerande' det är för att kunna påstå något om mina tekniska förmågor åt framtida kunder/uppdragsgivare. Några förslag här? 🤔

Hobbyprojekt
Det blir att fortsätta med det funktionsbaserade PHP-ramverket för utvecklingens skull för att hålla igång "PHP"-musklerna. I takt med att jag genomförde detta Uppdrag så fick jag idéer, funderingar, och allmänna tankar om hur det kan effektiviseras så det bara går att börja konfigurera auktoriserade ändpunkter/ruttrar, hantera data/kontrollers och sedan visa en slutlig vy i slutändan. En API-baserad variant får ske i ett senare skede i det hobbyprojektet.

Ett annat hobbyprojekt jag har i tankarna är en simpel träningsapp vars UI är för att jag själv ska kunna lägga till övningarna för ett givet gympass och sedan bli färdig och gå vidare med mitt liv. Super Slim Gym App, typ "Träna & Gå vidare!" kanske den ska heta! 😂

Vidareutbildning
Jag funderar som sagt att titta på Kubernetes för att komma igång med sjösättningsaspekterna av webbutveckling. Jag bör även kika på NextJS och ReactJS då det verkar vara vanliga IT-lösningar i Sverige om jag minns rätt? I alla fall ReactJS-delen?🤔 Nu väntar jag mig inte att fundamental förståelse och tillämpning av Kubernetes kommer få mig att folk helt plötsligt kontaktar mig på LinkedIn dock!

På återseende!

Mvh,
WKF.
---------
✔️HT2022-VT2024 TWEUG Webbutvecklings-programmet 120hp (distans)

Visa signatur

(V)ulnerabilities
(I)n
(B)asically
(E)verything
Programming

Permalänk
Medlem

Jag tycker du ska ha stor eloge som överhuvudtaget nämnde tillgänglighet och haft det i åtanke. Tillgänglighet är jävligt jobbigt att arbeta med, framförallt i SPA.

Får dock nästan halv panik av att se ren js - det finns en anledning till att alla kör react/vue/angular då man får mycket gratis

Efter att ha läst alla dina inlägg kändes det nästan som det saknade en ordentlig kravspec vid start av arbetet. Problemet när man är ensam är också att det saknas testare, allt man får på en vanlig arbetsplats.

Finns det en anledning till att du inte söker ordinarie anställning, mer än hemarbete? Känns som många kommer dra sig för att anställa en färsking. Undrar också varför du valde en 2-årig högskoleexamen och inte en 3-årig kandidat.
Mvh

Visa signatur

CPU: Ryzen 5600xGPU: 1080 TI ROG Strix RAM:2x16GB G.skill Trident @ 3600MHz MoBo: Asus B550FPSU: Corsair SF750
En resa till Nordkorea
2 dagar i Tjernobyl

Permalänk
Skrivet av Pelegrino:

Jag tycker du ska ha stor eloge som överhuvudtaget nämnde tillgänglighet och haft det i åtanke. Tillgänglighet är jävligt jobbigt att arbeta med, framförallt i SPA.

Får dock nästan halv panik av att se ren js - det finns en anledning till att alla kör react/vue/angular då man får mycket gratis

Efter att ha läst alla dina inlägg kändes det nästan som det saknade en ordentlig kravspec vid start av arbetet. Problemet när man är ensam är också att det saknas testare, allt man får på en vanlig arbetsplats.

Finns det en anledning till att du inte söker ordinarie anställning, mer än hemarbete? Känns som många kommer dra sig för att anställa en färsking. Undrar också varför du valde en 2-årig högskoleexamen och inte en 3-årig kandidat.
Mvh

Tjo, tack så mycket för att du läser samt dina inspel!

Utmaningen med webbtillgänglighet tycker jag är att kunna testa det med samma program som faktiska funktionsvarierande slutanvändare använder sig av. En sak jag tänker med SPA när den hämtar nytt "UI" är att återställa vart första TAB-knappen kommer att hamna så att det blir logisk navigering på senast inladdade "UI" i SPA:t.

Jag älskar vanilla JS även om det kan framstå rätt så "caveman"-aktigt! Utmaningen jag har med ramverken är främst att kunna nyttja TS(X) då jag inte kan TS ännu tillräckligt bra trots att jag pluggat hårdtypade C#.NET. En frustration med alla dessa JS-ramverk måste ju inte bara vara antalet som finns utan också när de genomgår större förändringar (liknande frustration i C#.NET tänker jag?).

Ibland undrar jag om ramverksskaparna förnyar sina ramverk enbart för att rättfärdiga sina ekonomiska bidrag/stöd de får från diverse bolag medan de själva kanske aldrig använder ramverken själva i samma utsträckning som många av dess faktiska användare gör?🤔

Det finns ett dokument med Kravspecifikation över diverse undersidor och vad på ett ungefär de ska innehålla. Under uppdragets gång så var det främst jag som kom på "Det här kan vara till nytta och det här kan vara QoL-höjande!" Vid nästa uppdrag hos denna Uppdragsgivare får jag ta fram en mer strikt Kravspecifikation med fler detaljer för varje undersida. En utmaning från Uppdragsgivarens sida med att ta fram Kravspecifikationen är ju just att de är inte lika IT-insatta som jag är och därmed också kanske inte heller vet vad som är möjligt och på så vis inte riktigt kan specificera vad de vill ha alla gånger.

Beträffande anställning så älskar jag friheten trots det dubbeleggade att med 100 % frihet så kommer även 100 % ansvar som egenföretagare! Webbutvecklingsprogrammet på distans var endast på 2 år men det fanns möjlighet att läsa ett år ytterligare för att få en kandidatexamen i datateknik men jag skippade det för jag tyckte att kurserna som ingick där var för icke-webbutvecklingsinriktade plus att jag hade inte kvar någon CSN längre efter dessa 2 år och jag hade ej lyckats kunna kombinera det med distansarbete samtidigt kände jag då.

Nu med utbildningen klar och snart ett par referenser så får referenserna, de tidigare projekten och hobbyprojekten vara det som kan leda till framtida Uppdrag!🫡

Mvh,
WKF.

Visa signatur

(V)ulnerabilities
(I)n
(B)asically
(E)verything
Programming

Permalänk
Medlem
Skrivet av WebbkodsFrilansaren:

Tjo, tack så mycket för att du läser samt dina inspel!

Utmaningen med webbtillgänglighet tycker jag är att kunna testa det med samma program som faktiska funktionsvarierande slutanvändare använder sig av. En sak jag tänker med SPA när den hämtar nytt "UI" är att återställa vart första TAB-knappen kommer att hamna så att det blir logisk navigering på senast inladdade "UI" i SPA:t.

https://www.nvaccess.org/download/. Är man nyfiken kan man läsa på om WCAG så står det om hur det är förväntat att saker uppför sig. Detta är dock överkurs (men ett lagkrav för offentliga hemsidor i Danmark och snart även privata).

Citat:

Beträffande anställning så älskar jag friheten trots det dubbeleggade att med 100 % frihet så kommer även 100 % ansvar som egenföretagare! Webbutvecklingsprogrammet på distans var endast på 2 år men det fanns möjlighet att läsa ett år ytterligare för att få en kandidatexamen i datateknik men jag skippade det för jag tyckte att kurserna som ingick där var för icke-webbutvecklingsinriktade plus att jag hade inte kvar någon CSN längre efter dessa 2 år och jag hade ej lyckats kunna kombinera det med distansarbete samtidigt kände jag då.

Nu med utbildningen klar och snart ett par referenser så får referenserna, de tidigare projekten och hobbyprojekten vara det som kan leda till framtida Uppdrag!🫡

Mvh,
WKF.

Så länge man trivs så - jag själv tycker det är väldigt härligt att jobba för ett större konsultföretag så att man kommer in i stora, samhällskritiska projekt och får prova på en massa häftiga saker

Visa signatur

CPU: Ryzen 5600xGPU: 1080 TI ROG Strix RAM:2x16GB G.skill Trident @ 3600MHz MoBo: Asus B550FPSU: Corsair SF750
En resa till Nordkorea
2 dagar i Tjernobyl

Permalänk

Webbutvecklingsdagbok - efter studierna

Jobb & Uppdrag
I måndags fick jag håret klippt för att inte se ut som en drulle framför webbkameran vid framtida nätbaserade kundmöten. Det är också skönt att slippa nacksvetten!😂

Sedan i tisdag fick jag ett par mindre "HTML-uppdrag" från en tidigare Uppdragsgivare nere i Stockholm som jag har haft i över fyra år nu(!) vilket jag arbetade med igår och även idag och har lite kvar imorgon. Dock är ersättningen där inte den högsta men det enda jag gör är att skriva h1-h6 HTML-rubriker inuti en HTML-fil utifrån rubriker från läromedel erhållna i stora PDF-filer som ibland får Acrobat att krascha.

Men en rolig sak som inträffade på "uppdragshåll" sedan måndagen var att jag fick kontakt med en person på ett nätforum som jag senare hade ett spontant Teams-möte med i cirka en timme vilket jag senare fick fakturera för. Nu har samma person hört av sig igen och gett mig förtroendet att fixa en sak på deras WordPress-baserade webbplats där jag redan har fått åtkomst till - jag tackar allra ödmjukast för det anförtrodda förtroendet!🫡

I det troligen korta uppdraget verkar det luta mot att använda template-page.php-filer och sedan nyttja $_GET-arrayen för att hämta ett angivet id inuti URL-fältet för en viss undersida som sedan använder detta för att läsa in en undersida från en spårningssida inuti ett iframe-element i dess src-attribut. Självfallet blir det allra högsta graden av säkerhet😎 med URLEncoded, datavalidering och -sanering så inget tok kan råka inträffa. Det är mycket tur att spårningsnumren är hexadecimal, det vill säga: /[0-9a-f]+/. Kontroll att det endast är från en viss URL äger givetvis också rum!

Jag läste på "nätet" att med hjälp av JS beroende på satt origin-policy så ska det gå att komma åt innehållet inuti iframe-elementet så det går att ta bort saker som inte önskas att ska visas efter det har laddats in. Det mesta måste laddas in först dock så att CSS:en från webbsidan följer med. Exempelvis tänkte jag plocka bort en div som inte är önskvärd att ha med.

Jag funderade först på cURL i PHP och sedan bearbeta HTML-resultatet men hur blir det då med CSS:en när den sedan skrivs ut?🤔 Jag misstänker starkt att CSS:en från webbplatsen inte appliceras om jag inte på något vis inkluderar dess stilmall externt. Och då blir det ju nästan som om vi har gjort en egen variant av ett iframe-element här. Så varför krångla till det?

"Om du ändå ska göra någonting så kan du lika gärna göra det ordentligt utan att överdriva såklart. Gör det ordentligt - med sunt förnuft!"
- WKF.

Imorgon fredag kommer jag att delta vid ett nätbaserat evenemang kallat "Fredagsfika" vilket är en Google Meet med några dussintals andra IT-intresserade/-verkande personer. Ämnet verkar vara "Prototyp och MVP" och för en gångs skull så har jag ju nu ett tidigare avslutat uppdrag som jag kan berätta utifrån mitt perspektiv som självgående IT-frilanskonsult med bara chatGPT4o och Gemini som IT-mentorer!🤣

(En rolig kuriosa är att vid ett tidigare fredagsfika jag var med på så var det för flera månader sedan innan jag ens var färdig med utbildningen och då hade jag inte fått mitt allra första 100 % IT-webbaserade uppdrag så det blir som om jag deltar denna gång som bokstavligen talat "digi-utvecklad!")

Och nästa vecka ska jag på en lokal lunchträff(?) IT Tech Meetup typ där lunch ingår då jag lyckades roffa åt mig en "lunch-API-nyckel"😁 och nu kan jag för en gångs skull prova att knyta kontakter för nu är jag "färdigutbildad" från skolan men såklart miltals ifrån "färdiglärd" inom webbutvecklingssfären.

Idag fick jag även mejl från min tidigare exjobbgivare och numera uppdragsgivare om att det ska firas att det första delmålet är uppnått (=lanseringen av webbplatsen och det unika programmet med brädspelet och den digitala modulen jag har utvecklat de senaste åtta veckorna sedan en vecka tillbaka). Det blir en Afterwork vid uppdragsgivarens kontor någon gång i oktober eller november.

Nästa delmål för denna uppdragsgivare är såklart att landa sin allra första kund. Jag avrådde uppdragsgivaren från att lägga massa slantar på SEO då det finns så mycket bedrägerier kring det (t.ex. "Jag får dig på första sidan på några veckor!" vilket är skitsnack om du inte sedan snabbt vill bli permanent avindexerad från Google, Bing, Yahoo & Altavista🤔).

Jag rekommenderade att prova annonsering på Google med fast budget och så klart det klassiska: ta proaktivt kontakt med potentiella kunder för de kanske inte ens vet att Ni finns och därmed kommer de knappast att söka efter er. Uppdragsgivaren är mycket karismatisk med goda ledaregenskaper så det ska inte vara några problem!

Avslutningsvis för denna gång på "Jobb & Uppdrag"-fronten så gick jag nyligen med i Slackgruppen(?) "Frilansare Sverige" där jag sa att jag är WKF "känd från internet" så om Du ser mig där så vet Du mitt förnamn från och med då!😲🤯😱

Hobbyprojekt
Jag hoppade in en snabbis i mitt RDP-projekt igår och fick lite ont i magen (likt i vissa kurser för cirka två år sedan) när jag insåg att, "Här var det ostrukturerat och väldigt spaghetti!" Fast det var inte att det var många funktioner i något som är 99 % funktionsbaserat utan snarare att det fanns ingen rimlighet i vilken ordning saker och ting ska köras och vad som ska göra vad.

Exempelvis har jag en funktion som ska kontrollera i en array om en angiven/tillåten ändpunkt hopknutet med tillåten HTTP-metod finns eller inte. Men i samma funktion så ser jag nu att det även finns anrop till och om angående auktorisering vilket jag inser nu är två skilda ansvarsområden.

Först ska jag göra det så lite "working proof of concept" som möjligt... MVP med andra ord... och sedan kan jag börja lägga in mer komplexitet som exempelvis möjligheten för konfiguration via en array som heter 'options' vilket i sin tur kan innehålla extra saker att göra för en given tillåten HTTP-metod och ändpunkt i arrayen med sådana.

Börja med att få något att faktiskt fungera och sedan bygg vidare på det!

Vidareutbildning
Inget nytt att rapportera.

På återseende!

Mvh,
WKF.
---------
✔️HT2022-VT2024 TWEUG Webbutvecklings-programmet 120hp (distans)

Visa signatur

(V)ulnerabilities
(I)n
(B)asically
(E)verything
Programming

Permalänk

Webbutvecklingsdagbok - efter studierna

Jobb & Uppdrag
Idag blev det överenskommet ett mycket kort uppdrag på en och en halv arbetsdagar att fixa ett par undersidor i WordPress åt ett svenskt bolag så att deras kunder kan följa sina försändelser genom att ange rätt spårningsnummer vilket sedan blir en del i ett src-attribut inuti ett iframe-element. Det är en sträng i formatet hexadecimal vilket kontrolleras via regex annars visas felmeddelande istället för ett iframe-element.

Först var det tänkt att nyttja ett REST API från tredjeparttjänsten men det visade sig att den inte innehåller all nödvändig information. En del i dess JSON-svar är en URL vilket i sin tur länkar till det som nu dynamiskt visas inuti iframe-elements src-attribut.

Det finns även en statisk div och denna div inklusive iframe-elementet ska kunna visas snyggt både mobilt och stationärt. Sju olika varianter (olika data i statiska div) skapades och jag gjorde det enkelt för kunden att nu kunna byta ut variabelvärdena i det statiska (skriva inuti enkelfnuttar i strängvariabler) utan att råka röra någon känslig CSS och/eller HTML. Jag glömde nämligen att fråga i förväg om de olika statiska data utöver bilderna annars hade jag kunna fixat det också men jag ska fråga kund om jag ska föra in det också åt dem! 🫡

Det som var utmanande var att få CSS:en att fungera korrekt då jag skrev inline CSS inuti vanilla PHP där CSS-selektorerna ska tävla mot WordPress CSS, Elementor Pro CSS och Crocoblock CSS. Och just det, glöm inte heller den CSS som finns inbakad från webbsidan som finns inuti iframe-elementets src-attribut vilket tvingar en att anpassa sig delvis utifrån hur den vill ta plats och lägga sina element vid olika skärmupplösningar! Jag har ju inte rört WordPress på ett mycket bra tag men jag kände till underbara template-filnamn.php konceptet.

Detta gör i princip att du kan välja en färdig mall när du ska skapa ny sida i WordPress och då WordPress den PHP-filen i all vanilla PHP-ära. Självfallet inkluderar jag sidhuvudet och sidfoten företaget har så det fortfarande ser ut som att det är deras webbplats.

Till slut så fick jag till det så att det mer eller mindre liknar som kunden designade det att se ut via en Elementor Pro Page. Då fick jag även lite inblick i Elementor Pro och dess tillämpning i WordPress. Det verkar relativt så användarvänligt men det behövs ett externt plugin för att kunna nyttja REST API data inuti diverse element varav varför jag valde vanilla PHP vägen av säkerhetsskäl (=det tar onödigt lång tid att säkerhetsgranska ett random WordPress plugin).

En aspekt som jag visste kanske inte skulle fungera var om jag kunde använda JavaScript för att i efterhand ändra diverse element inuti själva iframe-elementet via windowContent. Det visade sig dessvärre att det var ej tillåtet när jag provade att konsollogga elementet efter att det laddats in (troligen någon CSP och/eller CORS-policy). Så detta gjorde att det blev till att kunna få till CSS:en så bra som möjligt.

Nu finns det en sak kvar i det mycket korta uppdraget att få färdigt imorgon så att det fungerar korrekt då jag lovade att allt ska vara "up-and-running" tills nästa måndag. Ja, jag arbetar lite på helgen och jag debiterar inte extra för "obekväm arbetstid" för jag har för närvarande inte den "lyxen"!🙃

Hobbyprojekt
Inget nytt att rapportera.

Vidareutbildning
Inget nytt att rapportera mer än att jag trodde att idag kl15:00 så skulle det vara "Fredagsfika" i form av en Google Meet men det visade sig att det är nästa vecka. Var väl jag som var för optimistisk?!🤣 Nästa vecka blir det lunchträff på onsdag där föreläsningar inom IT kommer att ges lokalt här nere på stan.

Möjligen kommer att jag få träffa ett par ansikten som jag annars bara har pratat med i en Discord-grupp. Eller ja, ena har jag träffat två gånger tidigare men andra har jag inte träffat ännu men vi kanske var på samma tidigare lunchträff utan att jag visste om det då?🤔

På återseende!

Mvh,
WKF.
---------
✔️HT2022-VT2024 TWEUG Webbutvecklings-programmet 120hp (distans)

Visa signatur

(V)ulnerabilities
(I)n
(B)asically
(E)verything
Programming

Permalänk

Webbutvecklingsdagbok - efter studierna

Jobb & Uppdrag
En kort uppdatering idag: Igår så slutförde det jag korta uppdraget på 1,5 arbetsdagar och kunden rapporterade att denne var/är mycket nöjd med slutresultatet. Vidare berättade kunden att denne är mycket glad över vår spontana kontakt över nätet och att denne person kommer att kontakta mig för framtida koduppdrag!

Jag skickade den första fakturan (ja just det, jag glömde berätta att jag sa att de kunde makulera den tidigare fakturan på en timme för ett Teams-möte som tack för det allra första mycket korta uppdraget) och sedan tog jag i princip helg.

Nästa vecka så blir det som sagt var först ett fysiskt lunchnätverkande på onsdag nere på stan och sedan på fredag digitalt Fredagsfika med förhoppningen att kunna nätverka där också. Sistnämnda tror jag dock kommer att bli mer som att "hänga vid den digitala lägerelden med nya främlingar som senare kanske konverteras till bekanta" än något faktiskt nätverkande som skulle kunna leda till något nytt uppdrag men du vet inte förrän du provat flera gånger om!

Jag kommer också att kika på att förnya mitt webbhotell (inklusive förknippad IP-adress) hos min webbhotelleverantör i tre år rakt av så det är gjort. Det löper annars ut den 2:a oktober 2024. För övrigt så har jag ett domän som löpte ut 31:a augusti 2024 som fortfarande ligger kvar fast jag inte vill ha kvar det längre, så det står "Förnya omedelbart" men det tänker jag inte göra så det bör ju försvinna snart från min lista över tjänster?!🤔

Hobbyprojekt
Inget nytt att rapportera.

Vidareutbildning
I en Discord-grupp jag är med i så pratas det lite om COBOL och jag frågade en erfaren person där om huruvida det kan vara "lönt" / "värt" att lära sig COBOL och göra något mindre hobbyprojekt för att ha något unikt att visa upp. Nu tänker jag samtidigt att sannolikheten att jag kammar hem ens någon praktikplats vid en bank eller annan finansiell sektor som använder COBOL flitigt är mer eller mindre lika med 0.

Men det kanske kan vara en intressant "knorr" att ha med i sin kunskapsbeskrivning?🤔 Det jag ska ta reda på är hur utvecklingsmiljön för COBOL ser ut på Windows-datorer för tanken är att hobbykoden som skapas ska kunna i princip kunna kompileras och/eller sjösättas direkt till stordatorer.

Detta sistnämnda leder till en sak som jag störde mig en hel del på under min Webbutvecklingsutbildning på distans: riktigt undermåliga erhållna kunskaper om att sjösätta olika diverse skapade webbplatser/webbtjänster ut i olika produktionsmiljöer (t.ex. Azure, AWS/Vercel, egen VPS, med flera).

För om jag inte ens kan få ut en skapad "webbprodukt" i en önskad produktionsmiljö, så blir det ju rätt så "meh"? Tanken är ju att inte bara sjösätta utan också testköra det i den tänkta produktionsmiljön för att se så att det verkligen fungerar i skarpt läge. Klassiska meme:n "det funkar hos mig i localhost!" är inte kul längre när ens dagliga levebröd hänger på det!

Detta är också varför jag är sugen på hela biten med nätverksaspekterna inom Webbutveckling inklusive olika sjösättningsparadigmer såsom Docker, Kubernetes, virtuella miljöer, och de mer "ovanligare"(?) produktionsmiljöerna såsom de för exempelvis COBOL, Ruby on Rails, Erlang med Elixir, med flera.

Det är som sagt var mycket tuffa tider nu och för att kunna stå ut från mängden bland nyutexaminerade så gäller det nästan att vara en slags "Kodrenässansmänniska" vilket är en person som kan väldigt mycket olika saker. Jag vet och inser att samtidigt är det viktigt att specialisera sig eftersom tid är begränsat.

I samma veva tänker och tycker jag att en Webbutvecklare ska kunna rätt så mycket om alla steg inom webbutvecklingen för att kunna göra det enklare (mindre huvudvärk) för övriga led. T.ex. koda bra så SecOps inte får magsjuka över all minnesläckande och/eller icke-validerande CRUD-kodbaser ute i produktionsmiljöer!🤣

På återseende!

Mvh,
WKF.
---------
✔️HT2022-VT2024 TWEUG Webbutvecklings-programmet 120hp (distans)

Visa signatur

(V)ulnerabilities
(I)n
(B)asically
(E)verything
Programming

Permalänk
Medlem
Skrivet av WebbkodsFrilansaren:

. .

Jag kommer också att kika på att förnya mitt webbhotell (inklusive förknippad IP-adress) hos min webbhotelleverantör i tre år rakt av så det är gjort. Det löper annars ut den 2:a oktober 2024. För övrigt så har jag ett domän som löpte ut 31:a augusti 2024 som fortfarande ligger kvar fast jag inte vill ha kvar det längre, så det står "Förnya omedelbart" men det tänker jag inte göra så det bör ju försvinna snart från min lista över tjänster?!🤔
..

Det är bara att vänta så försvinner det. Tyvärr är det alltid så att om man glömmer förnya en domän så löper den ut. De skickar dig inte till inkasso. Så många driftstörningar som orsakats av att man glömt betala fakturan. Så det är något att ha i bakfickan. Se till att fakturan skickas rätt och att man överlåter domänen till IT som tar hand om de andra.

Permalänk

Webbutvecklingsdagbok - efter studierna

Jobb & Uppdrag
Nu ska vi se... det var drygt tio dagar sedan senast jag uppdaterade här. Jag har därför ett till webbfönster öppet så att jag kan se vad jag skrev senast så jag inte upprepar mig i onödan ("DRY"😁).

Okej, förra veckan så skulle jag på lunch-IT-möte under onsdagen men samma tisdag så fick jag en hel del jobb från min numera fyraåriga kund nere i Stockholm vilket jag behövde prioritera.

Däremot deltog jag i ett Fredagsfika under fredagen samma vecka. Senast jag var med där var för ett par månader sedan när jag fortfarande studerade tror jag?🤔 (någon onödigt investerad läsare i min dagbok kanske vet exakt senast jag var med där enligt mina egna rapporter här! )

Sedan denna vecka så fick jag ytterligare jobb från Stockholmskunden vilket jag blev klar med idag. Igår - onsdag - så deltog jag i något som hette #indiehackers evenemang via Google Meet där jag fick kontakt med en mycket ambitiös marknadsförare som har avsagt sig uppdrag för att köra 100 % på något där jag har hoppat in som Webbutvecklare (varav min tråd om andras användarupplevelser om plattformslösningen Bubble.io).

Jag tänker mig att jag behöver bygga upp en portfölj och jag har får än så länge rätt så mycket jobb från min fyraårige Stockholmskund så jag behåller en buffert under tiden jag deltar i detta "Allt-eller-inget"-projekt. Läs mer om det under "Hobbyprojekt" eftersom det kan klassas mer som hobby eftersom det inte finns någon ersättning i dagsläget - men stor potential! 🫡

Ja just det!!! Mitt under onsdagsevenemanget på Google Meet så kikade jag i min e-post och såg ett mejl från min tidigare Uppdragsgivare. Uppdragsgivaren rapporterade nu att de har ett par kunder på gång som kommer att kunna testköra den digitala modulen jag har bidragit med under åtta veckors tid i samverkan med Uppdragsgivarens medarbetare.

En annan sak sedan förra uppdateringen här så hade Uppdragsgivaren meddelat via mejl om ett AW vid deras huvudkontor drygt en mil från där jag bor. AW:et är tänkt att fira milstolpen att en ny produkt har lanserats av Uppdragsgivaren som nu börjar veva in de första - förhoppningsvis - betalande kunderna. Det sistnämnda innebär möjligtvis fler (det heter fler och inte mer när det talas om antal och inte intensitet / Mvh, Ponduspostulerande Språkpolisen) framtida uppdrag för min del.

För övrigt så är jag annars "uppdragsfri" och letar givetvis efter nya kodbaserade uppdrag utöver det arbetet jag får från min Stockholmskund på tisdagar. Nu hoppar vi till den spännande händelsen från igår!

Hobbyprojekt
Vad var det då egentligen som inträffade igår under #indiehackers evenemanget i Google Meet? Jo, först så kom det ett par nya ansikten som jag inte tidigare hade sett från tidigare Google Meet-evenemang arrangerat av samma arrangör.

Sedan så hörde jag att denna person hade beslutat sig för att förverkliga en potentiell affärsidé som personen hade gått och funderat på väldigt länge. Personen har en bakgrund inom marknadsföring så personen har genomfört redig marknadsföringsundersökning.

Och jag med bara "hobbymarknadsföringskunskaper" kan lära mig mycket av ett proffs som har arbetat inom industrin flera år om jag ska ha förstått personen rätt. Det som då hände var att efter evenemanget så tog jag och denna person ett nytt snack i ny Google Meet och idén lades fram lite mer konkret inklusive att en handlingsplan presenterades.

Vi är nu i samma Slack-grupper inklusive en privat där det finns två marknadsförare, en UI/UX-designer och jag som den enda Webbutvecklaren. (Jag verkar alltid hamna i situationer där jag är den enda Webbutvecklaren?!🤣 Möjligen är UI/UX-designer också frontendare!?)

Det hela är som sagt var på hobbynivå då det inte finns någon ersättning att talas om ännu förrän en skarp lansering av webbappen först. Ja, det är en webbapp med fokus på ett särskilt marknadssegment vilket denna mycket duktiga person arbetar med att specificera mer genom diverse marknadsundersökningar och andra förundersökningsaktiviteter från personens sida. Personen är mycket ambitiös så jag ser exalterat mycket fram att få samarbeta med personen och förhoppningsvis förverkliga detta hobbyprojekt så att det blir ett etablerat AB om redan bara ett par månader!

Hur det än kommer att gå så kommer jag att kunna nätverka, utbyta erfarenheter, och möjligen få lära mig UI/UX-riktlinjer för att själv ta mina frontend-förmågor till nästa nivå!😎

Jag hoppade som sagt var på detta projekt som en scen från "Yes Man" för jag behöver ändå bygga upp min portfölj. Och denna idé tror jag starkt har större potential än mina idéer om en svensk och en engelsk webbplats som lär ut Webbutveckling som om jag skulle ha varit den första i Sverige att ha tänkt på den idén!😅

Vad jag kan berätta om projektet mer om att det är en webbapp är att det finns en Figma-prototyp som går att utgå ifrån och utifrån den ska då en första MVP-version utvecklas av mig - antingen via Bubble.io och/eller annan plattformslösning vilket kommer att diskuteras ihop med samtliga parter i projektet.

(Språkpolisen igen: jag växlar mellan hobbyprojekt och projekt här av ren lathet men jag syftar på ett projekt som för närvarande är på hobbynivå dvs., ingen ersättning ännu men förhoppningsvis inom kort - ett par månader!)

Nu kanske det svävar orosmoln när du läser om hur mycket jag tjatar om att ingen ersättning finns att tillgå ännu. Här har jag en filosofi: "Du kan bara bli blåst en gång av samma person!" och blir du blåst fler gånger så är det mer ditt fel än den andres fel även om det kanske var den som "startade" det hela!

Jag tänker även att "Om jag är så duktig på det jag gör så skulle det snarare bli en förlust för personen att försöka blåsa mig eftersom jag då skulle upphöra bidra med det jag är så duktig på!" Och till sist så har alla involverade parter våra personliga varumärken att värna om.

För flera år sedan så minns jag hur en kund på en gig-marknadsportal skrev i stil med att att, "I have now made an upfront payment. I trust you since I have my honor and you have your reputation at stake!" Möjligen kanske det låter lite "passiv-aggressivt" men det jag tycker det är ett bra sätt att sålla ut de som är seriösa vs oseriösa självgående IT-baserade konsulter (dvs., de som arbetar på distans).

Likt autonoma drönare så får vi helt enkelt se vart detta projekt landar någonstans om ett par veckor!😁

Vidareutbildning
För några dagar sedan så chattade jag med chatGPT4o eller "chatGPT Auto" som det numera heter. Det är gratisversionen vilket innebär ett antal meddelanden från mäktiga chatGPT o1 Preview eller vad det är.

Och den snackar mycket, men det fanns en sak som jag störde mig på: allt tjat om färdiga bibliotek så fort jag frågade om hur någonting egentligen fungerade eller var kodat som. Vad jag var intresserad av var hur PHPMailer faktiskt fungerade "under the hood" och då enligt chatGPT o1 så är det via socketanslutning till SMTP-protokollet där du sedan använder stream_get_contents().

Sedan kan du "tugga" igenom strängar som börjar med svarskoder och sedan texter med endast stora bokstäver vilket är i princip alternativ för vad du kan skicka för kommando sedan. Du börjar så klart HELO eller för snabbt skrivet EHLO och sedan vid 250 som tycks vara OK svarskod så vill du begära STARTTLS för att skapa säker anslutning efteråt via stream_socket_enable_crypto().

Att skriva till den etablerade anslutningen via stream_​socket_​client() sker via fwrite() då det inte tycks finnas någon stream_socket_write() typ. fwrite() verkar fungera som så att den vill skriva till en stream-resurs så då ska det inte vara några problem.

Det ska bli spännande om jag kan göra en väldigt förenklad version av PHPMailer som bara tar emot anslutningsuppgifter, etablerar anslutning, kräver TLS och sedan startar det och sedan skickar ett mejl med till, från, ämne och innehållet i både HTML och icke-HTML. Två nästa steg efter det vore att få till stöd för DKIM och bifogade filer.

På återseende!

Mvh,
WKF.
---------
✔️HT2022-VT2024 TWEUG Webbutvecklings-programmet 120hp (distans)

Visa signatur

(V)ulnerabilities
(I)n
(B)asically
(E)verything
Programming

Permalänk

Webbutvecklingsdagbok - efter studierna

Jobb & Uppdrag
Jag har haft gott om jobb innan slutet på förra månaden från kunden i Stockholm dock är det jobbet ej webbutvecklingsrelaterat och med lägre arvode timvis.

Jag har inte hört något mer från Uppdragsgivaren om hur det går för denne att hitta kunder vilket i sin tur kan skapa fler uppdrag från Uppdragsgivaren i bästa fall.

Inte heller har jag hört något från personen som behövde hjälp med ett och ett halvdagars arbete inom WordPress-sfären. (Ja, jag känner till det pågående kaoset inom WordPress just nu!)

En intressant sak är dock att i samband med att jag har ett pågående hobbyprojekt med fyra andra personer - med techstacken React Native Expo på frontend-sidan medan backend-sidan använder Hono, någon form av SQL (SQLite eller PostgresSQL; det kommer bli ett vettigt databasval inom kort) vilket i sin tur är sjösatt hos tyska Hetzner - så kommer jag att kunna dra nytta av lärdomarna från det hobbyprojektet.

Låt mig få kort förklara...

Det jag har gjort åt min tidigare Uppdragsgivare var en webbaserad applikation medan önskemålet så klart hade varit en mobilbaserad app eller mobilapp förkortat. Nu i samband med att jag lär mig React Native Expo så kommer jag sedan att kunna applicera de kunskaperna för att ta fram en mobilapp åt den tidigare Uppdragsgivaren då jag - förhoppningsvis - har lärt mig allt som behövs från skapandet till sjösättningen i både Play & App Store.

Så då skulle jag kunna sälja in en mobilapp någon gång i framtiden åt tidigare den Uppdragsgivaren. Om jag minns rätt så blir det möjligen Afterwork med Uppdragsgivaren någon gång i början på nästa månad.

Hobbyprojekt
"Kodtärningen" är kastad och jag har gett mig in i React Native Expo vilket för några dagar sedan var lättsamt att skapa nytt projekt men idag när jag skulle göra samma sak mot en GitHub Organisationsskapat repo så fick jag uppleva Dependency Hell för allra första gången i min kodkarriär.

Följande Meta(?)-relaterade paket fungerade ej att installera:

babel-plugin-react-compiler

Jag insåg fort då att något var helt fel för jag hade inte gjort några förändringar i min övriga utvecklingsmiljö så något var helt fel. När jag då kikade på Issues för GitHub-repot så tro inte f*n att det är fler som har exakt samma fel som jag.

En lösning som föreslogs av någon var något jag aldrig tidigare jag har gjort vilket är override inuti package.json-filen:

"overrides": { "babel-plugin-react-compiler": "0.0.0-experimental-734b737-20241003" },

Då helt plötsligt gick det och allt var som vanligt för några dagar sedan. Vad jag kan meddela vilket säkert gör många besvikna nu och kanske smått av lite förbannade är att jag kodar i JSX och TSX då en YT-guide jag följer gör det.

Och nu handlar det om att få ut en "good enough" MLP (inte MVP) som ett första utkast. Nedan återfinns kod för _layout.jsx (ja, det är helt fel fil för det, men det fixar sig de kommande dagarna):

import { Text, View, Image, Button, SafeAreaView, Pressable, } from "react-native"; import useDynamicStyles from "../assets/styles/styles.jsx"; import { useFonts } from "expo-font"; import * as SplashScreen from "expo-splash-screen"; import { useEffect } from "react"; SplashScreen.preventAutoHideAsync(); export default function App() { // Load styles based on color scheme (light or dark) const s = useDynamicStyles(); // Load all fonts before rendering const [loaded, error] = useFonts({ "Lato-Black": require("../assets/fonts/Lato/Lato-Black.ttf") }); useEffect(() => { if (loaded || error) { SplashScreen.hideAsync(); } }, [loaded, error]); if (!loaded && !error) { return null; } // Render app return ( <> <SafeAreaView> <Image style={[s.imageXY("100%", 360)]} source={require("../assets/images/onboarding-1.png")} /> </SafeAreaView> <View style={[s.container]}> <Text style={[ s.Lato-Black, s.colorTextGreen, s.fontSize(24), s.lineHeight(30.17), s.marginTop(32), ]}> Alla dina rattmuffar på ett ställe </Text> <Text style={[ s.Lato-Black, s.colorTextGreen, s.textCenter, s.fontSize(18), s.lineHeight(22.5), s.marginTop(8), s.paddingX(16), ]}> Oavsett var du lagrar dina rattmuffar så ska det vara lätt! </Text> <Pressable style={[ s.buttonWidthHeight(328, 48), s.colorPrimaryBackground, s.textCenterInButton, s.marginTop("auto"), s.borderRadius(50), ]}> <Text style={[ s.Lato-Black, s.colorTextWhite, s.fontSize(18), s.lineHeight(21.6), ]}> Prova Rattmuffar Gratis </Text> </Pressable> <Pressable style={[ s.buttonWidthHeight(328, 48), s.colorWhiteBackground, s.textCenterInButton, s.marginTop(8), s.marginBottom(32), s.borderRadius(50), s.borderStyleWidthColor("solid", 1, "#014235"), ]}> <Text style={[ s.Lato-Black, s.colorTextGreen, s.fontSize(18), s.lineHeight(21.6), ]}> Logga in </Text> </Pressable> </View> </> ); }

Den senior jag samarbetar med som agerar lite mer som stöd och "idébollare" med än snarare någon som ser över axeln på mig sa dock att det jag har gjort hittills är inte hur denne person hade gjort det. Och något annat hade ju bara varit förvånande: aldrig att jag hade kunnat göra så många rätt redan från början?!

En liten frågsam axelryckande upptäckt är att Pressable-element behövs för att kunna skräddarsy utseendet för annars vanliga Button-element i React Native Expo. Jag trodde det "fundamentala" för knappar vilket är i princip en av de få sätt du kan interagera med skulle vara lite mer välarbetat, men det är vad det är som sagt.

Du som har läst min resa under min Webbutvecklingsutbildning augusti 2022 t.o.m. maj 2024 vet att jag senare fick stor kärlek för funktionell programmering. Så klart har jag därför en styles.jsx-fil som innehåller funktioner för att snabbare kunna skriva style-attributen i vyelementen:

import { StyleSheet, Appearance, useColorScheme } from "react-native"; // All Styles are placed here for the entire app const useDynamicStyles = () => { const colorScheme = useColorScheme(); // Returns either "light" or "dark" return StyleSheet.create({ buttonWidthHeight: (width, height) => { return { width: width, height: height }; }, mainBackground: { backgroundColor: colorScheme === "light" ? "#FFF9ED" : "#060606", }, colorPrimary: { color: colorScheme === "light" ? "#014235" : "#AFF4C6", }, colorPrimaryBackground: { backgroundColor: colorScheme === "light" ? "#014235" : "#AFF4C6", }, LatoBlack: { fontFamily: "Lato-Black" }, textCenter: { textAlign: "center" }, textCenterInButton: { alignItems: "center", justifyContent: "center" }, textLeft: { textAlign: "left" }, textRight: { textAlign: "right" }, textJustify: { textAlign: "justify" }, }); };

Koden ovanför är dock bara delar utav den även om det inte är så att jag har skrivit någon hemlighetsstämplad kod som exempelvis superoptimerade algoritmer eller diverse "Unique Selling Proposition"-baserad kod.

Vad du ser i "stilfilen" i koden ovan är hur jag blev riktigt trött på att behöva skriva måsvingar överallt och koden ovan visar nog också varför senioren ej hade valt att göra som jag har gjort. Men viktigast nu är att få ut det på ett pålitligt och snabbt sätt som är det för mig främst då jag ansvarar 100 % för React Native Expo-skapandet.

Det sistnämnda har jag tackat personen som jag kom i kontakt med för ett par veckor sedan under ett Fredagsfika att personen fortfarande anförtror mig. I takt med att detta kodprojekt blir större och mer börjar likna vad det är tänkt att vara för något så kommer jag dessvärre att kunna visa mindre av det - så du vet!

Mobilappen är delvis en CRUD-app däremot - något annat skulle bara ha varit häpnadsväckande. En sak jag måste säga - ironiskt nog - är att utvecklingen av React Native Expo-appar är roligare än att behöva skriva responsiv CSS-kod för webbappar som också ska fungera på mobiltelefoner.

Här i React Native Expo har du istället siffror som dynamiskt sedan anpassar sig på mobila enheter skärmar. Dock är det porträttläge som gäller enbart just nu så nästa steg mycket längre fram är versionen som stöder både mobiler och surfplattor.

Du kan även se i _layout.jsx-koden hur style-attributen i de olika elementen påminner om dynamisk TailwindCSS-kod. Visst finns NativeWind och jag har tipsats om Tamagui på andra håll men då kan det bli en onödigt längre inlärningskurva och bättre att nöta grunderna innan man hoppar på ramverk för ramverk, eller hur?!🤪

De intressanta utmaningarna med React Native Expo blir däremot:
- Få till att vissa Views endast visas när en är inloggad kontra inte, dvs., auth-biten.
- Få till att vissa data inte hämtas för mycket i onödan när Views hoppas mellan ofta.

(Hojta gärna till med ett svar här om Du vet vad som är typiska branschstandarder och/eller "quick n' dirty"-lösningar för dessa två punkter ovan!)

Låt mig få utveckla vad jag menar med andra punkten ovan. Om du använder en app där du hämtar data via ett API som appen har åtkomst till efter lyckad inloggning så kanske den visar något. När du sedan hoppar till en annan vy och sedan går tillbaka till vyn som fetchar data så vill du ju inte hämta samma data i onödan.

Ponera tusentals och senare tiotusentals användare som hoppar mellan olika vyer så vill du ju inte tvinga fram samma HTTPS GET om det skulle kunna finnas lagrat lokalt likt någon motsvarande lösning till localStorage som finns i webbläsarna.

Förresten så kommer jag hela tiden att använda JavaScript och/eller PHP när jag pratar om vissa saker som jag inte ännu vet vad deras motsvarigheter i React Native Expo heter/är för något. Samma sak gör jag när jag promptar LLM:er: Jag frågar vad motsvarande - om det finns - är för något i React Native Expo för att påskynda det hela. För jag vet ju oftast vad exakt jag vill kunna göra, frågan är då bara hur i just React Native Expo.

(Har jag uppnått rätt mängd för sökordet React Native Expo nu kära sökmotorer?🤣)

Till sist så lovar jag här och nu att denna mobilapp INTE kommer att radera alla dina data så fort du tillfrågas om du vill spara dina icke-sparade ändringar. Dina HTTPS PUTs kommer att hanteras med allra yttersta försiktighet och omtanke!😁

Nu har min kund från Stockholm skickat mig mer arbete som jag ska arbeta med så jag kan fortsätta med React Native Expo om ett par dagar igen!🫡 (hobbyprojektgruppen är redan meddelade om detta och kände till det sedan innan så...)

Vidareutbildning
I princip kan jag säga att jag håller på att lära mig React Native Expo från grunden så gott som det går med hjälp av internets diverse olika källor (Officiell dokumentation, LLM:er, Discord- & Slack-grupper).

På återseende!

Mvh,
WKF.
---------
✔️HT2022-VT2024 TWEUG Webbutvecklings-programmet 120hp (distans)

Visa signatur

(V)ulnerabilities
(I)n
(B)asically
(E)verything
Programming

Permalänk

Webbutvecklingsdagbok - efter studierna

Jobb & Uppdrag
Jag var för ovanlighetens skull inne på LinkedIn en snabbis idag och såg då ett meddelande från en av mina Uppdragsgivare. Det gällde om kommande Afterwork fysiskt på plats vid deras kontor cirka en mil bort från där jag bor. Detta kommer att preliminärt äga rum någon gång i slutet på nästa månad.

Idag blev jag också färdig med en annan kunds typiska veckoarbete. Därefter slängde jag mig in igen i hobbyprojektet vilket antingen kan lyfta eller inte om en eller ett par månader. Bland annat meddelades det idag i hobbyprojektgruppen att nu går det att lansera appar för granskning i Google PlayStore och Apple App Store.

Hobbyprojekt
Jag har nu börjat lära mig använda Pressable-elementen i React Native Expo och hela kruxet med den så kallade "Stack"-navigeringen:

// app\index.jsx import { Text, View, Image, Button, SafeAreaView, Pressable, } from "react-native"; import useDynamicStyles from "../assets/styles/styles.jsx"; import { useFonts } from "expo-font"; import * as SplashScreen from "expo-splash-screen"; import { useEffect } from "react"; import { StatusBar } from "expo-status-bar"; import { Link } from "expo-router"; SplashScreen.preventAutoHideAsync(); export default function App() { // Load styles based on color scheme (light or dark) const s = useDynamicStyles(); // Load all fonts before rendering const [loaded, error] = useFonts({ "Lato-Black": require("../assets/fonts/Lato/Lato-Black.ttf"), useEffect(() => { if (loaded || error) { SplashScreen.hideAsync(); } }, [loaded, error]); if (!loaded && !error) { return null; } // Render app return ( <> <SafeAreaView> <Image style={[s.imageXY("100%", 500)]} source={require("../assets/images/onboarding-1.png")} /> </SafeAreaView> <View style={[s.container]}> <Text style={[ s.MerriweatherBlack, s.colorTextGreen, s.fontSize(24), s.lineHeight(30.17), s.marginTop(32), ]}> Alla dina rattmuffar på ett ställe </Text> <Text style={[ s.LatoRegular, s.colorTextGreen, s.textCenter, s.fontSize(18), s.lineHeight(22.5), s.marginTop(8), s.paddingX(16), ]}> Oavsett var du lagrar dina rattmuffar - ska det vara lätt att göra rätt </Text> <Pressable style={[ s.buttonWidthHeight(328, 48), s.colorPrimaryBackground, s.textCenterInButton, s.marginTop("auto"), s.borderRadius(50), ]}> <Text style={[ s.LatoRegular, s.colorTextWhite, s.fontSize(18), s.lineHeight(21.6), ]}> Pröva Grodd Gratis </Text> </Pressable> <Link href="/login" asChild style={[ s.buttonWidthHeight(328, 48), s.colorWhiteBackground, s.textCenterInButton, s.marginTop(8), s.marginBottom(32), s.borderRadius(50), s.borderStyleWidthColor("solid", 1, "#014235"), ]}> <Pressable> <Text style={[ s.LatoRegular, s.colorTextGreen, s.fontSize(18), s.lineHeight(21.6), ]}> Logga in </Text> </Pressable> </Link> </View> </> ); }

Denna app\index.jsx körs då tack vare:

// app\_layout.jsx import { Stack } from "expo-router"; const RootLayout = () => { return ( <> <Stack> <Stack.Screen name="index" options={{ headerShown: false }} /> </Stack> </> ); }; export default RootLayout;

Och så finns det login.jsx och register.jsx på samma app\-root nivå just nu. Jag har problem med Stack-navigeringskonceptet än så länge. Det blir något knas med hur den ska visa navigeringshistoriken (det du ser högst uppe till vänster i mobilen för att gå tillbaka till föregående skärm).

Först och främst så visar den filnamnet så det står "<- login" fast det ska stå "<- Tillbaka". För det andra så får jag inte till med gruppering - när mappar heter (mappnamn) - och navigeringen till olika komponentfiler där.

Jag läser hos Docs.Expo.Dev men har inte blivit tillräckligt klokare ännu. Det är just det här med "Stack.Screen" och dess attribut som används. Har ej kopplat ännu för mig. Jag föreställer mig att tanken ska vara att jag ska kunna strukturera upp så att jag kan ange undermapp och sedan komponentfil medan _layout-filen i mappen ska utgöra mallen för vad som syns för alla de grupperade filerna?🤔

Så här ser "Logga in" respektive "Registrera" (de använder samma inmatningsfält i princip):

import { Text, TextInput, View, SafeAreaView, Pressable } from "react-native"; import useDynamicStyles from "../assets/styles/styles.jsx"; import { useEffect, useState } from "react"; import { StatusBar } from "expo-status-bar"; import { Link } from "expo-router"; import ErrorBox from "../components/ErrorBox.jsx"; const Login = () => { // Load styles based on color scheme (light or dark) const s = useDynamicStyles(); // Use state to store user input (email and password) const [email, setEmail] = useState(""); const [password, setPassword] = useState(""); // Use state to set input border colors and text colors const [inputBorderTextColors, setInputBorderTextColors] = useState("#35685E"); // Use state to either show or not show error message const [showError, setShowError] = useState(""); // onPress "Logga in" button const handleLogin = () => { // Set error box when it is empty if (email === "" || password === "") { setShowError("Ange e-post och lösenord"); return; } // Set error box when email is not valid format if (!email.includes("@")) { setShowError("Ogiltig e-postadress"); return; } }; // useEffect to hide error message when input fields change. // Also reset colors of input fields. Both use the same color. useEffect(() => { setShowError(""); setInputBorderTextColors("#35685E"); }, [email, password]); // useEffect to change input field border colors and text colors // when error message is shown useEffect(() => { if (showError) { setInputBorderTextColors(s.colorErrorText.color); } }, [showError]); return ( <SafeAreaView style={[s.container]}> <View style={[s.marginX(16)]}> <Text style={[ s.MerriweatherBlack, s.colorTextGreen, s.textLeft, s.width("100%"), s.fontSize(24), s.lineHeight(30.17), s.marginTop(72), ]}> Logga in </Text> <Text style={[ s.LatoRegular, s.colorTextGreen, s.textLeft, s.fontSize(18), s.lineHeight(22.5), s.marginTop(8), ]}> Oavsett var du lagrar rattmuffar - ska det vara lätt att göra rätt </Text> <Text style={[ s.LatoRegular, s.colorTextGreen, s.textLeft, s.width("100%"), s.fontSize(16), s.lineHeight(20), s.marginTop(32), ]}> E-post </Text> <TextInput style={[ s.borderStyleWidthColor("solid", 1, inputBorderTextColors), s.LatoRegular, { color: inputBorderTextColors }, s.borderRadius(4), { alignSelf: "stretch" }, s.height(48), s.backgroundColor("#FFFFFF"), s.marginTop(8), s.padding(10), s.fontSize(16), s.lineHeight(20), ]} onChangeText={(text) => setEmail(text)} value={email} placeholder="E-post" /> <Text style={[ s.LatoRegular, s.colorTextGreen, s.textLeft, s.width("100%"), s.fontSize(16), s.lineHeight(20), s.marginTop(24), ]}> Lösenord </Text> <TextInput style={[ s.borderStyleWidthColor("solid", 1, inputBorderTextColors), s.LatoRegular, { color: inputBorderTextColors }, s.backgroundColor("#FFFFFF"), s.borderRadius(4), s.marginTop(8), s.paddingX(16), s.paddingY(12), s.fontSize(16), s.lineHeight(20), { alignSelf: "stretch" }, ]} onChangeText={(text) => setPassword(text)} value={password} placeholder="Lösenord" secureTextEntry={true} /> {showError && <ErrorBox ErrorMessage={showError} />} <Pressable onPress={handleLogin} style={[ s.buttonWidthHeight(328, 48), s.colorPrimaryBackground, s.textCenterInButton, s.marginX("auto"), s.marginTop(24), s.borderRadius(50), ]}> <Text style={[ s.LatoRegular, s.colorTextWhite, s.fontSize(18), s.lineHeight(21.6), ]}> Logga in </Text> </Pressable> </View> <Text style={[ s.LatoRegular, s.colorTextGreen, s.textCenter, s.width("100%"), s.fontSize(16), s.lineHeight(28), s.marginTop(16), ]}> Har du inget konto?{" "} <Link style={[ s.LatoRegular, s.colorTextGreen, s.Weight700, s.borderBottomWidth(1), ]} href="/register"> Skapa konto </Link> </Text> </SafeAreaView> ); }; export default Login;

Observera att funktionen handleLogin() är en "work-in-progress". Den är tänkt att kontrollera mot något hårdkodat än så länge fast jag tycker att jag lika gärna kunde ha fått kontrollera mot något API på webben. Men men! Senioren föreslog hårdkodat än så länge!

Annars så fungerar den egna skräddarsydda komponenten som visar angivet felmeddelande i dess ErrorMessage-attribut:

// components\ErrorBox.jsx (ligger utanför app\-mappen) import { View, Text } from "react-native"; import useDynamicStyles from "../assets/styles/styles.jsx"; import React from "react"; // ErrorBox component that takes error message as prop const ErrorBox = ({ ErrorMessage }) => { // Use the useDynamicStyles hook to get styles const s = useDynamicStyles(); // Return a View element with the Error message return ( <View style={[s.colorErrorBox, s.marginTop(16)]}> <Text style={[ s.colorErrorText, s.LatoRegular, s.fontSize(16), s.lineHeight(28), s.paddingY(8), s.textCenter, ]}> {ErrorMessage} </Text> </View> ); }; export default ErrorBox;

Två saker som fungerade bra här som jag är glad över är att useFonts() inte behöver köras igen utan den verkar på något vis lagra typsnitten i minnet för alla övriga komponenter under appens körning. Andra saken är att även useDynamicStyles() fungerar på olika komponentnivåer eller vad det nu ska kallas för.

Eller ja, just det! Vad jag blev mest nöjd över hittills var faktumet att useState() kunde uppdatera ett färgvärde vilket också uppdaterade utseendet. Om React Native Expo är som vanliga React så borde den alltså via useState() i samverkan med useEffect() rendera om komponenten och därmed dess uppdaterade färgvärden?🤔

Sedan vid kontroll idag så visade det sig att inte allt såg ut som önskat på mobiltelefonen via Expo Go. Främst vissa element verkar inte vilja renderas riktigt rätt. Möjligen kommer ena "delägaren" i hobbyprojektet att låna ut en gammal iPhone till mig som låter mig få ett "halvhum" om hur det kan se ut på ett ungefär hos vissa iOS-enheter.

Nästa steg blir nu att faktiskt få till API-kommunikation och diverse "global states":
1) om du är inloggad eller inte så ska vissa saker visas och inte,
2) om du växlar mellan ljus/mörkt tema så ska appens utseende reflektera (ha!) det

Det jag visat hittills är inte precis hemlighetsstämplade algoritmkoder med orealistiskt hög avkastning så ingen fara att dela med sig (än så länge).

Den genomgående kodstrukturen får säkert många erfarna React Native Expo-utvecklare att må illa, vilket jag ber om ursäkt så här på efterhand!😂

(Psst! Vad är det för funktion som rekommenderas att användas när någon har lyckats logga in på appen? Finns det någon relaterad "router.push(/'inloggad')"-funktion som går att använda här?)

Vidareutbildning
Jag fortsätter sakta men säkert att lära mig React Native Expo - både dess mysiga saker (relativt simpla "CSS"-kodande) och hemska saker (de faktiska mobilenheterna renderar inte alltid som det ser ut i webbläsarens mobila läge).

På återseende!

Mvh,
WKF.
---------
✔️HT2022-VT2024 TWEUG Webbutvecklings-programmet 120hp (distans)

Visa signatur

(V)ulnerabilities
(I)n
(B)asically
(E)verything
Programming

Permalänk
Skrivet av WebbkodsFrilansaren:

Jag läser hos Docs.Expo.Dev men har inte blivit tillräckligt klokare ännu. Det är just det här med "Stack.Screen" och dess attribut som används. Har ej kopplat ännu för mig. Jag föreställer mig att tanken ska vara att jag ska kunna strukturera upp så att jag kan ange undermapp och sedan komponentfil medan _layout-filen i mappen ska utgöra mallen för vad som syns för alla de grupperade filerna?🤔

Kul att se React Native i sin enklaste form! Suttit en del med det och var längesen man fick se det i sitt bare!

Angående denna frågan så har jag för mig att den heter headerbacktitle men det kan också vara react navigation som jag använde då :/

Permalänk
Skrivet av Yellowcandy:

Kul att se React Native i sin enklaste form! Suttit en del med det och var längesen man fick se det i sitt bare!

Angående denna frågan så har jag för mig att den heter headerbacktitle men det kan också vara react navigation som jag använde då :/

Tjo, tack så mycket för den snabba återkopplingen!

Men React Native Expo är ju React Native via Expo-ramverket så då är det väl inte så "bare"? Vad är annars nästa abstraktionslager ovanpå React Native Expo?!

Btw, kan det vara "Redirects": https://docs.expo.dev/router/reference/redirects/ som är lösningen för att skicka vidare en användare som lyckades logga in? 🤔 I samma veva måste jag då fixa första "global state" så att en inloggad inte kan gå tillbaka till inloggningsvyn utan att först logga ut.

Global State Management är ju jättekul i React!😬

Mvh,
WKF.

Visa signatur

(V)ulnerabilities
(I)n
(B)asically
(E)verything
Programming

Permalänk

Webbutvecklingsdagbok - efter studierna

Jobb & Uppdrag
Inga nya uppdateringar från tidigare Uppdragsgivare, varken den åtta veckors långa eller den som endast varade en och en halv arbetsdag. Däremot kanske jag får lite småjobb att göra som vanligt denna tisdag från Stockholmskunden.

Därför hoppar vi direkt till det så kallade "hobbyprojektet" vilket kanske "inom kort™" leder till ersättning och då kan bekrivas här istället för under rubriken "Hobbyprojekt".

Hobbyprojekt
Jag visste redan jag hoppade på detta spännande hobbyprojekt att förr eller senare skulle jag behöva svälja en - åtminstone för mig - jobbig "kodgroda", nämligen TypeScript. Gamla minnen från min Webbutvecklingsutbildning på distans under kursen Webbutveckling III där ett delmoment var TypeScript så försökte jag mig på att skriva inmatningsvalidering men TypeScript blev så förbannad på mig under kompileringstillfället att jag backade!

Sedan dess så skippade jag TypeScript resten av utbildningen även när jag skrev interaktiv kod åt min Uppdragsgivare. Tack vare rejäla kontroller av vad för slags data (och inte bara rådata) som tas emot på serversidan vid anrop så blev det ändå "typstrikt". Jo, TypeScript transkompilerar inte "typat" JavaScript utan det är bara under kodandet. Zod(?) tror jag rekommenderas om man vill testköra att typerna fungerar som tänkt.

Hursomhelst så fick jag den välmenande ordern från senioren i det än så länge hobbyprojektet att konvertera om alla JSX-filer till TSX. Så jag köttade igenom en 4-timmars YT-video om grunderna i TS även om jag kände till grunderna såsom annoteringar i variabler, funktionsanrop, parametrar, returvärden. Mest faktisk aha-upplevelse var grejen med Generiska funktioner vilket jag upplever att jag sett en hel del av i diverse TSX-kod.

I och med att StyleSheet.create({}) inte - på något enkelt 'out-of-the-box' vis - tillåter funktioner som objektegenskaper så valde jag att skriva vad som kan beskrivas som mycket ful kod:

// All Styles are placed here for the entire app const useDynamicStyles = () => { const colorScheme = useColorScheme(); // Returns either "light" or "dark" return StyleSheet.create({ buttonWidthHeight328_48: { width: 328, height: 48 }, indexImage: { width: "100%", height: 500 }, fontSize16: { fontSize: 16 }, fontSize18: { fontSize: 18 }, fontSize24: { fontSize: 24 }, height48: { height: 48 } }, }); };

Detta gjorde då att jag kunde skriva så här för utseendet tills vidare:

import { View, Text } from "react-native"; import useDynamicStyles from "../assets/styles/styles"; import React from "react"; // ErrorBox component that takes error message as prop export const ErrorBox = ({ ErrorMessage, Switch, }: { ErrorMessage: string; Switch: boolean | string | null; }) => { // Use the useDynamicStyles hook to get styles const s = useDynamicStyles(); // Return a View element with the Error message // if "Switch" is FALSE, NULL or empty string then return NULL if (!Switch || Switch === "" || Switch === null) { return null; } // Return the ErrorBox component return ( <View style={[s.colorErrorBox, s.marginTop16]}> <Text style={[ s.colorErrorText, s.LatoRegular, s.fontSize16, s.lineHeight28, s.paddingY8, s.borderRadius4, s.textCenter, ]}> {ErrorMessage} </Text> </View> ); };

Notera användningen här av import React from "react"; för att det ska fungera. Här måste jag dock ange typerna för de variabler och notera hur jag nu har en "Switch"-variabel jag la till för att slippa skriva i stilen:

{showError & <ErrorBox ErrorMessage={showError}/>}

Utan nu är det bara - tycker jag - mer stiliga:

<ErrorBox ErrorMessage={showError} Switch={showError} />

Ja, Switch reagerar att det finns innehåll, dvs., inte är false, null eller en tom sträng.

För någon dryg timma sedan hade jag ett kort uppföljningsmöte med Gänget­™ där jag äntligen fick reda på lite mer av upplägget för serversidan och det än så länge enbart senioren sköter vilket är serverns samverkan med databasen. Det hela ska utvecklas inte med ett REST API utan så kallade GraphQL.

Det sistnämnda trodde jag först var en slags grafbaserad databas men tydligen ska det vara Enterprise-lösning för att genomföra dataanrop mot server som i sin tur talar med databasen. Så det jag ska skicka är så kallade:

gql` query FindRattmuffar { Rattmuffar { id, more_data, name, and_, _so, _on} } `;

Dessutom när jag kikar på faktisk webbkod så skickas följande vid anrop (utöver HTTPS-säkra kakor):

{ "operationName": "FindRattMuffar", "query": "query FindRattMuffar {\n rattmuffar {\n id\n createdAt\n updatedAt\n name\n userId\n }\n}", "variables": {} }

Så tydligen ska operationName och den faktiska databasförfrågan (query) skickas med och eventuella variabler i vissa fall. När jag går igenom ett par YT-klipp om React Native (Expo) med GraphQL så kommer jag att få reda på hur "branschstandard" detta är. Släppt 2015 av Meta som själva använder det (precis som React de tagit fram(?)) så undrar jag ändå om det är vanligt i branschen eller om detta är ett fall av "Vi skapade det, så såklart använder vi det då!"?

Det andra korta jag fick reda på om GraphQL är att du gör antingen en query (motsvarande SELECT i SQL) eller en mutation (motsvarande INSERT, DELETE, UPDATE i SQL) inom GraphQL. Så nu ska jag kika på hur GraphQL används inom React Native Expo och vilka GraphQL-bibliotek som rekommenderas mest för just det ändamålet!

(Om Du har och/eller fortfarande använder GraphQL i React Native (Expo) så hojta gärna till vad Du rekommenderar för GraphQL-bibliotek vilket stödjer HTTPS-kakor!🫡)

Vidareutbildning
Jag fortsätter sakta men säkert att lära mig React Native Expo - både dess mysiga och mindre mysiga utmanande saker och ting. Nu läggs GraphQL-baserat API till i vidareutbildningen!

På återseende!

Mvh,
WKF.
---------
✔️HT2022-VT2024 TWEUG Webbutvecklings-programmet 120hp (distans)

Visa signatur

(V)ulnerabilities
(I)n
(B)asically
(E)verything
Programming

Permalänk

Webbutvecklingsdagbok - efter studierna

"Tjo igen, Gänget!😎" som jag numera säger på Slack när jag har något att uppdatera i Hobbyprojektet.

Jobb & Uppdrag
Inga nya Uppdrag eller sökta Jobb. Däremot var det en hel del arbete från Stockholmskunden de två senaste veckorna, denna inräknat. Inom kort blir det dags att göra sig mer sedd inom "Cybervärlden" via diverse kommunikationskanaler inklusive sociala medier och så vidare!

Hobbyprojekt
Det så kallade Hobbyprojektet för en mobilapp i React Native Expo går framåt samtidigt som jag upplever stor ovisshet om huruvida jag gör överhuvudtaget någonting "enligt branschstandard" när jag följer officiell dokumentation.

Om många inom IT-världen vill vara konkurrenskraftiga så ligger det ju delvis i deras intresse att hemlighetshålla så mycket som möjligt. Å andra sidan så efterfrågas duktiga utvecklare så det hela blir lite som arbetsmarknadens erfarenhetskrav men ingen får erhålla erfarenhet.

En stor utmaning jag har för närvarande är en relativt så sammanhängande kodstruktur då stor del av officiell dokumentation är små kodsnuttar där vissa saker då blir helt irrelevanta om en inte har tillräckliga kunskaper att kunna extrapolera från det.

Ta något så fundamentalt såsom det så kallade autentiseringsflödet. Något sådant finns givetvis men för mig än så länge är det utmanande att anpassa det till projektet. Hursomhelst så får Du gärna ta en titt på nuvarande lösning från mig:

Här är _layout.tsx i den huvudsakliga appen och tanken är att få till en ternary så att endast autentiserade ("privata") skärmar visas vid inloggning:

import { Text, View, Image, Button, SafeAreaView, Pressable, } from "react-native"; import useDynamicStyles from "../assets/styles/styles"; import { AuthProvider, useAuthContext } from "../context/AuthContext"; import { useFonts } from "expo-font"; import * as SplashScreen from "expo-splash-screen"; import { useEffect } from "react"; import { StatusBar } from "expo-status-bar"; import { Stack, useRouter } from "expo-router"; import React from "react"; const RootLayout = () => { return ( <> <AuthProvider> <Stack> {/* <PUBLIC SCREENS */} <Stack.Screen name="index" options={{ headerShown: false }} /> <Stack.Screen name="register" options={{ headerShown: false }} /> <Stack.Screen name="login" options={{ headerShown: false }} /> {/* <Stack.Screen name="(app)" options={{ headerShown: false }} /> */} {/* <PRIVATE SCREENS - SHOULD MIGRATE TO THE "(app)" FOLDER!!! */} <Stack.Screen name="auth_myrattmuffar" options={{ headerShown: false }} /> <Stack.Screen name="auth_information" options={{ headerShown: false }} /> </Stack> </AuthProvider> </> ); }; export default RootLayout;

Jag provade först med att ha AuthContext.tsx (se koden längre nedan här) direkt i _layout.tsx men då blev React Native (Expo)-kompilatorn(?) arg. Dock har jag sett någon implementering inom så kallade "autentiseringsflöden" där det ska gå att skapa kontexten som sedan används så att det går att kontrollera om en är inloggad innan några tillgängliga skärmar visas. Då kan du inte råka gå tillbaka till en skärm som inte ska gå när du är inloggad/inte inloggad.

Exempelvis kan du i nuvarande implementering gå tillbaka till index.tsx vilket inte ska gå när du är inloggad. Du undrar säkert varför det inte fungerar. Jo, för min useState() här måste alltid först ladda in typsnitt i minnet och dess boolean-värde (loaded) verkar inte finnas kvar sedan vilket gör att de övriga sakerna aldrig slår igenom och ingen router.replace() äger rum:

// Check auth after loading fonts useEffect(() => { if (loaded && !isLoading && isAuthenticated) { router.replace("/auth_myRattmuffar"); } }, [isAuthenticated, isLoading, loaded]);

Det där bör lösas dock när jag får till ternary redan i Stack-elementet. På tal om just autentisering så ser dess kontextkomponent så här enligt nedan.

Här är context\AuthContext.tsx vilket används för att säkerställa autentisering och därmed förhoppningsvis korrekt åtkomst i mobilappen:

import React, { createContext, PropsWithChildren, useContext, useEffect, useState, } from "react"; import AsyncStorage from "@react-native-async-storage/async-storage"; interface AuthContextType { user: String | null; setUser: React.Dispatch<React.SetStateAction<String | null>>; isAuthenticated: boolean; setIsAuthenticated: React.Dispatch<React.SetStateAction<boolean>>; isLoading: boolean; setIsLoading: React.Dispatch<React.SetStateAction<boolean>>; } const AuthContext = createContext<AuthContextType | undefined>(undefined); export const useAuthContext = () => { const context = useContext(AuthContext); if (!context) { throw new Error("useAuthContext must be used within an AuthProvider"); } return context; }; export const AuthProvider = ({ children }: PropsWithChildren) => { const [user, setUser] = useState<String | null>(null); const [isAuthenticated, setIsAuthenticated] = useState(false); const [isLoading, setIsLoading] = useState(true); useEffect(() => { const checkAuth = async () => { try { setIsLoading(true); const storedUser = await AsyncStorage.getItem("user"); if (storedUser) { setUser(storedUser); setIsAuthenticated(true); setIsLoading(false); } else { // User not found, not authenticated setUser(null); setIsAuthenticated(false); setIsLoading(false); } } catch (error) { console.error("Error checking authentication:", error); setUser(null); setIsAuthenticated(false); setIsLoading(false); } finally { setIsLoading(false); } }; checkAuth(); }, []); return ( <AuthContext.Provider value={{ user, setUser, isAuthenticated, setIsAuthenticated, isLoading, setIsLoading, }}> {children} </AuthContext.Provider> ); };

För att möjliggöra global hantering av huruvida en användare är inloggad/autentiserad eller ej. Lägg märke till att AsyncStorage för närvarande används. Jag ska byta ut det så snart som möjligt till Expo Secure Store.

Sedan används det exempelvis här i en komponent som kräver att användaren är inloggad (app\my_rattmuffar.tsx):

// Load styles based on color scheme (light or dark) const s = useDynamicStyles(); const [myRattmuffar, setMyRattmuffar] = useState([]); const router = useRouter(); const { isAuthenticated, isLoading, user } = useAuthContext(); // Check if user is authenticated useEffect(() => { if (!isLoading && !isAuthenticated) { router.replace("/login"); } }, [isAuthenticated, isLoading]);

För att sedan logga in så ser det ut så här (skarp varning för ej async & await; app\login.tsx):

// If we are here, then we can attempt to log in by using a fetch POST request // Prepare the JSON payload for the POST request const loginPayload = { username: email, password: password, method: "login", }; fetch(LOGIN.URL, { method: "POST", headers: { Accept: "application/json", "Content-Type": "application/json", }, body: JSON.stringify(loginPayload), }) .then((response) => { if (response.ok) { // Grab headers from response as a string let headerString = JSON.stringify(response.headers); // Remove the ""}}" at the end of the string and grab only the set-cookie part // and store it in async storage to be used to authenticate the user headerString = headerString.slice(0, -3).split('set-cookie":"')[1]; AsyncStorage.setItem("user", headerString); // Redirect user to "MyRattmuffar" screen //router.replace("auth_myrattmuffar"); setIsAuthenticated(true); } else { // Handle failed login by getting error message from JSON response return response.json(); } }) .then((data) => { if (data) { // Set error message from JSON response setShowError(data?.error || "Något gick fel. Försök igen."); } }) .catch((error) => { setShowError("Något gick fel. Försök igen."); }); };

I nuvarande upplägg så spelar det egentligen ingen roll vad som lagras i AsyncStorage då en kaka skickas med vid de faktiska fungerande CRUD-anropen mot backend. Jag hade enorm oro för det fanns information om att fler än en kakor samtidigt kunde strula i React Native (Expo). Men Senioren sa att trots att, "Det kan vara lite knepigt - så bör nätverksstacken i mobilens OS kunna hantera det".

Sanningens ögonblick kom sedan vid att hämta rattmuffar (app\auth_myrattmuffar.tsx):

const MyRattmuffar = () => { // Load styles based on color scheme (light or dark) const s = useDynamicStyles(); const [myRattmuffar, setMyRattmuffar] = useState([]); const router = useRouter(); const { isAuthenticated, isLoading, user } = useAuthContext(); // Check if user is authenticated useEffect(() => { if (!isLoading && !isAuthenticated) { router.replace("/login"); } }, [isAuthenticated, isLoading]); // Fetch rattmuffar data and store in state (myRattmuffar) useEffect(() => { let isMounted = true; const fetchMyRattmuffar = async () => { if (isMounted) { const response = await fetch(FIND_RATTMUFFAR.URL, { method: "POST", headers: { Accept: "application/json", "Content-Type": "application/json", }, body: JSON.stringify( buildGraphQuery(FIND_RATTMUFFAR.operationName, FIND_RATTMUFFAR.query) ), }); if (response.ok) { const data = await response.json(); setMyRattmuffar(data.data.Rattmuffar || []); // Loop through data.data.Rattmuffar and concate all "name" values into a string let rattmuffNames = ""; for (let i = 0; i < data.data.Rattmuffar.length; i++) { rattmuffNames += data.data.Rattmuffar[i].name + ", "; } Alert.alert("Frön hittades!: " + RattmuffarNames); } else { Alert.alert("Frön kunde ej hämtas?! " + response.status); setMyRattmuffar([]); } } }; fetchMyRattmuffar(); return () => { isMounted = false; // Set flag to false on unmount to prevent updates }; }, []); if (isLoading) { return null; } // Show fetched data return ( <SafeAreaView style={[s.container]}> <StatusBar style="auto" /> <View style={[s.marginX16, s.marginTop72, s.justifyBetweenRow]}> <Auth_Menu /> </View> <Auth_MyRattmuffar_List Rattmuffar={myRattmuffar} /> <Hemlig1RattmuffarBtn /> <Hemlig2RattmuffarBtn /> </SafeAreaView> ); }; export default MyRattmuffar;

Lägg märke till useEffect() som hämtar rattmuffar är konstruerad så att den inte kan råka hämta igen när komponenten nedmonteras. Detta inträffade annars när jag klickade på menyknappen och sedan "Logga ut". För övrigt så lyckades den skicka med kakan "magiskt" nog och för "proof-of-concept" så skrev jag ut dess namndata i Alert.alert().

Se utdrag från menykoden för utloggningshändelsehantering här (components\Auth_Menu.tsx):

const [open, setOpen] = useState(false); // On logout click const logoutClick = () => { setOpen(false); AsyncStorage.removeItem("user", () => { Alert.alert("Du har loggats ut!"); setIsAuthenticated(false); router.replace("/login"); }); }; return(<><Modal visible={open} transparent={true} animationType="slide"> <TouchableWithoutFeedback onPress={() => setOpen(false)}> <View style={[ { flex: 1 }, { width: 158 }, { height: 120 }, s.backgroundColorWhite, s.widthFull, s.textCenterInButton, ]}> <View style={{ width: 100 }}> <Pressable onPress={() => informationClick()} style={[ { marginBottom: 16 }, { alignItems: "flex-start" }, { marginHorizontal: "auto" }, { width: 100 }, ]}> <View style={[{ flexDirection: "row" }, { gap: 8 }]}> <Image source={require("../assets/images/menu-info-icon.png")} /> <Text style={[ s.LatoBold, s.fontSize18, s.lineHeight28, s.colorTextGreenLight, ]}> Information </Text> </View> </Pressable> <Pressable style={[ { alignItems: "flex-start" }, { marginHorizontal: "auto" }, { width: 100 }, ]} onPress={() => { logoutClick(); }}> <View style={[{ flexDirection: "row" }, { gap: 8 }]}> <Image source={require("../assets/images/menu-logout-icon.png")} /> <Text style={[ s.LatoBold, s.fontSize18, s.lineHeight28, s.colorTextGreenLight, ]}> Logga ut </Text> </View> </Pressable> </View> </View> </TouchableWithoutFeedback> </Modal></>)

Nu är det "rinse-and-repeat" tills att en MLP ("Most Lovable Product") bli färdig för lansering. Så visst lär jag mig delvis, fast för det mesta så förstår jag inte riktigt vad jag gör. I och med att det är "hobbyprojekt utan ersättning" (än så länge) så är det bara buga och tacka för det anförtrodda förtroendet jag fått från de så kallade "hobbyprojektägarna"!

Som sagt så kan jag ej kräva något faktiskt "mentorskap" från den deltagande Senioren i detta hobbyprojekt då ingen egentligen har några obligatoriska åtaganden gentemot varandra, mer än våra personliga varumärken på spel!?🤪

På tal om det sistnämnda så är det ju illa om jag inte lyckas prestera/leverera eftersom det får ju hela min Webbutvecklingsutbildning att framstå väldigt "LOL?!"🤔 Jag är också i "rävsaxen" att jag kan inte dra mig ur nu och erkänna mig "besegrad" för det skulle också spegla illa för det personliga varumärket. Så det är bara bita i det virtuella sura äpplet och "FÅ SKITEN GJORD!™"🫡

Vidareutbildning
Jag fortsätter sakta men säkert att lära mig React Native Expo - både dess mysiga och mindre mysiga utmanande saker och ting. Nu fortsätter GraphQL-baserat API till i vidareutbildningen såväl som det så kallade autentiseringsflödet för att underlätta när mobilappen skalas upp!😨

På återseende!

Mvh,
WKF.
---------
✔️HT2022-VT2024 TWEUG Webbutvecklings-programmet 120hp (distans)

Visa signatur

(V)ulnerabilities
(I)n
(B)asically
(E)verything
Programming

Permalänk

Webbutvecklingsdagbok - efter studierna

Jag ska nu rentvå mitt ökennamn "WebbKodsGnällaren™" genom att prata om spännande utmaningar i hobbyprojektet istället för att enbart uttrycka missnöjen med vissa av utmaningarna!😂

Jobb & Uppdrag
Inget nytt från Uppdragsgivaren men lite jobb från Stockholmskunden. Jag ska kontakta Uppdragsgivaren inom kort och fråga om det blir någon Afterwork för att fira den första milstolpen eller inte.

Hobbyprojekt
Den mobila appen i vad vi kan kalla hädanefter för Rattmuffsprojektet går framåt. Idag runt 11-tiden hade Gänget™ ett Google Meet-möte där vi gick igenom databasmodellen. Det finns delade - men ömsesidigt respekterade - åsikter mellan mig och Senioren kring hur (icke-)normaliserad det första utkastet av Rattmuffsdatabasen ska vara.

Exempelvis kommer varje Rattmuff att ha perioder uttryck i mellan månader - exempelvis mellan månad januari och februari. Däremot kan en rattmuff ha två perioder, exempelvis jan-feb och juni-juli. Senioren föreslår att vi då har fyra kolumner för att representera dessa istället för ny tabell som är kopplad till varje rattmuff (normalisering). Jag föreslår att ny tabell kan minska antalet kolumner i tabellen Rattmuff samtidigt som det går att lägga till obegränsat antal olika perioder per rattmuff.

Jag tänker det jag hörde någon databaslärare på YT säga, "Väx på höjden [nya rader i en eller flera tabeller] istället för på bredden [nya kolumner i en eller flera tabeller]!" och därmed normalisering som tillkommer. "Den dagen, den sorgen", får det bli då med icke-normaliseringen, även om jag tycker att, "Om du ska göra något så kan du lika gärna göra det ordentligt utan att överdriva!".

Vad har jag då gjort hittills gällande den mobila appen för den så kallade obfuskerade Rattmuffsappen?:

Det finns kod för att stödja flera olika språk (ja, just nu testar den bara efter svenska annars engelska som standardspråk):

import i18n from "i18next"; import "intl-pluralrules"; import { initReactI18next } from "react-i18next"; import * as Localization from "expo-localization"; import en from "@locales/en.json"; import sv from "@locales/sv.json"; const languageTag = Localization.getLocales()[0].languageTag; i18n.use(initReactI18next).init({ resources: { en: { translation: en }, sv: { translation: sv }, }, lng: languageTag.startsWith("sv") ? "sv" : "en", fallbackLng: "en", interpolation: { escapeValue: false, }, }); export default i18n;

För att koden ovan skulle fungera i React Native Expo så behövdes ett så kallat polyfill vid i form av import "intl-pluralrules";. Här förstår jag inte varför. Men det är vad det är!

Översättningsmodulen kan sedan importeras och nyttjas utan problem:

export default function App() { const s = useDynamicStyles(); const router = useRouter(); const { isAuthenticated, isLoading, user } = useAuthContext(); const { t } = useTranslation(); return ( <> <Text style={[ s.textFont, s.colorTextGreen, s.textCenter, s.fontSize24, s.lineHeight30_17, s.marginTop32, ]}> {t("index_text1")} </Text> </>);}

Det finns nu element som ser till att tangentbordet döljs när du klickar utanför inmatningsfält:

<TouchableWithoutFeedback onPress={() => Keyboard.dismiss()}> <TextInput style={[ s.borderSolidWidth1, { borderColor: inputBorderTextColors }, s.LatoRegular, { color: inputBorderTextColors }, s.borderRadius4, { alignSelf: "stretch" }, s.height48, s.backgroundColorWhite, s.marginTop8, s.padding10, s.fontSize16, s.lineHeight20, ]} onChangeText={(text) => setEmail(text)} value={email} placeholder="E-post" keyboardType="email-address" ref={emailRef} onSubmitEditing={() => passwordRef.current?.focus()} /> </TouchableWithoutFeedback>

Koden ovanför ser den också till att hoppa till nästa inmatningsfält när du klickar på Retur-tangenten på det virtuella tangentbordet på mobila enheter. Detta sker tack vare användningen av useRef() för att sedan kunna fokusera på det andra inmatningsfältet.

Idéägaren bakom detta Hobbyprojekt har många kontakter inom marknadsföring såväl som relaterad industri så det finns möjligen goda möjligheter att kunna lansera mobilappen mot tänkt målgrupp/marknadssegement.

Några framtida utmaningar nu:
Det finns en modal/dialog för att visa menyn vilket endast går att komma åt efter lyckad inloggning. Nu tänker jag att jag vill implementera liknande för att visa och CRUDa enskild rattmuff. Tänk så här:

1) Du loggar in och ser alla dina rattmuffar.

2) Du trycker på en enskild rattmuff som då visar sina detaljer. Här ser du också knappar för redigering och/eller radering.

3) När du trycker på redigering för den enskilda rattmuffen så kan det antingen visas en modal/dialog för det eller så tas du til en annan skärm för det. Frågan är vad som är enklast?🤔

Å ena sidan skulle det gå att skicka data som props till dialogen för att ändra och/eller bekräfta radering av enskild visad rattmuff och när den bekräftas så kan den nuvarande enskilda rattmuffen uppdateras genom att antingen uppdatera sin sida för att information ändrades eller så finns den ej kvar längre för den raderades och du förs till översikten över dina övriga rattmuffar?🤔

Jag har ingen aning om vad som är "branschstandard" gällande lösningsval. På tal om det sistnämnda så finns det ju bara kompromisser och inga fulländande lösningar - så möjligen "hugget som stucket🤷‍♂️" som min Stockholmskund brukar säga?!

En annan utmaning är den globala tillståndshanteringen av tema och språk. För närvarande så kontrollerar den vad enhetens färgschema och språkval är och nyttjar det sedan som standard för tema och språk i mobilappen. Frågan är när en klassisk sol-/måneikon läggs in och du ska kunna växla mellan mörkt och ljust tema. Jag antar att vad som behövs är en ThemeProvider-liknande lösning här?🤔

En tredje utmaning är avsaknaden av faktisk riktig middleware-implementering av autentisering i mobilappen. Just nu så finns det en autentiseringskontext vilket sedan kontrolleras när en komponent som kräver autentiseras laddas fram. Den kör då useContext() och kan sedan få åtkomst till nuvarande status om användaren är inloggad och sedan nyttjas en useState() som kan omdirigera användaren till inloggningsskärmen om den ej är inloggad längre.

Egentligen hade jag föredragit om detta kunde ha skett redan på <Stack/>-nivå där skärmarna finns och när en navigering sker så kontrolleras först inloggningsstatus innan en viss skärm överhuvudtaget visas. Jämför detta med klassisk middleware-kod i PHP eller NodeJS där du kan kontrollera om användaren är inloggad och/eller har åtkomst till viss API-ändpunkt på serversidan innan något annat körs.

Det som förvånar mig är att det verkar smått svårt att bara hitta "typiska standardlösningar" för detta för mobilappar med tanke på antalet mobilappar som har inloggningsstöd. Det är ju inte så att Rattmuffsappen är den första i världen på 10-15 år - eller hur många år nu mobila enheter har funnits - att vilja stödja autentiseringsbaserad skärmnavigering direkt i den mobila enheten.

I slutändan är det ju bara abstraktioner på abstraktioner för vad som bara är förändringar voltspänningar för att leda och/eller inte leda ström genom många transistorer?🤔😁

Vidareutbildning
Vidareutbildningen fortsätter i React Native Expo-världen.

På återseende!

Mvh,
WKF.
---------
✔️HT2022-VT2024 TWEUG Webbutvecklings-programmet 120hp (distans)

Visa signatur

(V)ulnerabilities
(I)n
(B)asically
(E)verything
Programming

Permalänk

Webbutvecklingsdagbok - efter studierna

Jobb & Uppdrag
Jag fick mejl idag från en (tidigare(?)) Uppdragsgivare att varumärket vars webbapp och webbplats jag tog fram åt Uppdragsgivaren nu har godkänts av Patent- och registreringsverket.

Uppdragsgivaren angav även i samma mejlutskick att information snart om en Afterwork kommer inom kort för att kunna få så många deltagande parter som möjligt att kunna delta samtidigt.

Hobbyprojekt
Jag har några snabba punkter att gå igenom angående det pågående Hobbyprojektet vars obfuskering är känt som den mobila rattmuffsappen via React Native Expo.

Path Aliases är livet och kärleken i stora välstrukturerade projekt!❤️
Jag glömde igår att nämna att jag även fixat så att jag äntligen kan använda så kallade Path aliases vid import av projektfiler. Tidigare hade jag strul med npx expo start -c där den misslyckades med (trans(?))kompileringen av filerna där require()-funktionen misslyckades för den kunde inte bearbeta flera "../" i rad utan tolkade den som en vilket gav fel filsökväg.

Med andra ord så tolkade den "../../../" (eller fler ../) som enbart "../" vilket så klart ej stämde och då kunde den ej importera nödvändiga flera. Detta skedde då när jag hade filer i två katalognivåer eller djupare. Tack vare Path aliases så går "@" att använda och sedan med hjälp av konfigurering i babel.config.js och tsconfig.json så fungerar det utan några som helst problem:

// babel.config.js module.exports = function (api) { api.cache(true); return { presets: ["babel-preset-expo"], plugins: [ [ "module-resolver", { alias: { "@assets": "./assets", "@components": "./components", "@constants": "./constants", "@hooks": "./hooks", "@contexts": "./contexts", "@utils": "./utils", "@locales": "./locales", }, extensions: [".js", ".jsx", ".ts", ".tsx"], }, ], ], }; }; // tsconfig.json { "compilerOptions": { "baseUrl": "./", "paths": { "@app/*": ["app/*"], "@assets/*": ["assets/*"], "@components/*": ["components/*"], "@constants/*": ["constants/*"], "@hooks/*": ["hooks/*"], "@contexts/*": ["contexts/*"], "@utils/*": ["utils/*"], "@locales/*": ["locales/*"] }, "target": "ES6", "jsx": "react-native", "module": "ESNext", "esModuleInterop": true, "forceConsistentCasingInFileNames": true, "strict": true, "skipLibCheck": true }, "extends": "expo/tsconfig.base" } // Exempel på användning - importera stilar till en tvåmapparsdjup TSX-fil! import useDynamicStyles from "@assets/styles/styles";

Vad gäller databasmodellen så blev det klart i Slack att nu verkar den officiella versionen av den vara framtagen. Jag ser dock ingen ny git commit i backend-koden att den skulle ha lagts in där. Jag kikade på GraphQL-YT-klipp igår om potentiella nackdelar med denna "mellanhand" som tydligen ska ligga mellan en server och/eller databas och klienter.

Är GraphQL överskattat trots att Facebooks mjukvaruingenjörer tog fram det?🤔
Det verkar kunna finnas risk för:
- Krascha GraphQL-servern genom komplexa satser (eng. "queries") eller andra sårbarheter.
- Dålig prestanda på grund av den så kallade N+1 databashämtningsproblematiken.

Den andra punkten är det jag funderar på om det är delvis bakom varför normalisering verkar vara ej önskvärt. Normalisering kräver JOINs i klassisk SQL och frågan är då om GraphQL:s resolvers kommer att göra två databashämtningar för att sedan via sin egen "databearbetningsmotor" kommer att slå ihop dessa utifrån rådande schemas.

Ta exempelvis att du hämtar alla Rattmuffar från en tabell och sedan alla användare från en annan tabell - det vill säga två enskilda databasanrop först - för att sedan slå ihop dessa så att du får alla användare och alla deras tillhörande rattmuffar per användare. Detta är en klassisk JOIN-sats i vanlig SQL medan i GraphQL:s resolvers så skulle det kunna bestå av två enskilda databasanrop vilket är oerhört ineffektiv?!

(Ja, i slutändan måste ju GraphQL översätta sitt eget frågesatsspråk till motsvarande databasspråk för att kunna kommunicera med faktiskt vald databas! - skicka en SQL- eller MongoDB-sats exempelvis)

Det ovannämnda är det jag länge funderat på hur (in)effektivt GraphQL kan göra med exempelvis MySQL/MariaDB/PostgreSQL utifrån hur det själv vill hantera relationer (=flera olika sammanhängande tabeller) i exempelvis MySQL/MariaDB/PostgreSQL jämfört med att bara ha jättestora tabeller så att du bara hämtar data från en tabell och sedan är saken biff.🤔

Om GraphQL kan skapa lika vackra JOIN-satser och sedan bearbeta data så att det skickas tillbaka i samma JSON-format som tillfrågades så är det ju underbart. Samtidigt så finns det ingen "magi" så det är ju alltid någon parsing som ska äga rum vilket betyder att 1:or och 0:or äger rum.

En petig säkerhetsdetalj att säkerställa kring vem som faktiskt genomför ett CRUD-anrop mot databasen!
En sista liten detalj som jag måste gå igenom med Senioren gällande användningen av GraphQL som (istället för REST) "API" är huruvida inloggningskakan innehåller information om användaren som går att kontrollera mot innan någon faktiskt databas-CRUD får äga rum.

Det finns GUUID utöver id för varje användare. Denna GUUID är vad som bör vara inbakat på ett oföränderligt sätt (t.ex. lagra kakan också på servern och/eller JWTs) så att en autentiserad användare inte kan efterfråga rattmuffsdata som någon annan användare har ensam rätt till bara för att deras GUUID har hamnat på mörka nätet.

Även hela biten med CSRF bör implementeras. Inte för att jag tror att någon är intresserad av att försöka sno någon annans rattmuffsdata. Men jag personligen anser att det reflekteras dåligt på en som nyutexaminerad Webbutvecklare om en miss på grund av ren och skär arkitekturmässig lathet skulle leda till att vem som helst med godkänd autentiserad inloggningskaka kan hämta ut andras data.🤦

Om Senioren väljer att avfärda det hela så kommer jag att bli mer "hm🤔" över dennes ambitionsnivåer i detta gemensamma hobbyprojekt. Om Du ändå ska göra något så kan du lika gärna göra det så ordentligt som det går utan att överdriva. Ett motargument jag dock har fått från Senioren tidigare är att det reflekteras väl på en att inte göra mer än nödvändigt för att komma vidare.

Å mitt motargument till det motargumentet är att det går att göra så rätt som möjligt från början utan att överdriva i form av att det skulle ta för lång tid. Jag har med andra ord redan fått smaka på så kallad "Utvecklingspolitik"!😂🤣

Vidareutbildning
Vidareutbildningen med React Native Expo fortsätter som vanligt!🫡

På återseende!

Mvh,
WKF.
---------
✔️HT2022-VT2024 TWEUG Webbutvecklings-programmet 120hp (distans)

Visa signatur

(V)ulnerabilities
(I)n
(B)asically
(E)verything
Programming

Permalänk
Medlem

Inte helt hundra på hur ditt autentiseringsflöde ser ut.

Men kan rekommendera att köra på t.ex. Auth0 eller något färdigt bibliotek för detta. (Om du ska bygga något professionellt åt någon kund d.v.s) Då hanterar de inloggningen åt dig. (Finns 2FA osv)

Där kan man även ställa in hur länge en access-token är giltig. En rimlig tid är cirka 60 minuter och för att man inte ska behöva logga in på nytt hela tiden så får man en "refresh-token" som kan användas för att hämta ut en ny token när token blir expired.

Auth0 sköter det mesta av denna biten.

https://auth0.com/docs/quickstart/native/react-native/00-logi...
Inte så mycket kod som krävs för inloggning.

const LoginButton = () => { const {authorize} = useAuth0(); const onPress = async () => { try { await authorize(); } catch (e) { console.log(e); } }; return <Button onPress={onPress} title="Log in" /> }

Sedan brukar man även ha roller/behörigheter på plats, så att man kan ha t.ex. "Administratör" eller "Vanlig användare" och sedan checkar man av dessa permissions både i front-/backend för att låsa ned/dölja viss funktionalitet.

Visa signatur

10700K | NVIDIA RTX 3080

Permalänk
Skrivet av kwame:

Inte helt hundra på hur ditt autentiseringsflöde ser ut.

Men kan rekommendera att köra på t.ex. Auth0 eller något färdigt bibliotek för detta. (Om du ska bygga något professionellt åt någon kund d.v.s) Då hanterar de inloggningen åt dig. (Finns 2FA osv)

Där kan man även ställa in hur länge en access-token är giltig. En rimlig tid är cirka 60 minuter och för att man inte ska behöva logga in på nytt hela tiden så får man en "refresh-token" som kan användas för att hämta ut en ny token när token blir expired.

Auth0 sköter det mesta av denna biten.

https://auth0.com/docs/quickstart/native/react-native/00-logi...
Inte så mycket kod som krävs för inloggning.

const LoginButton = () => { const {authorize} = useAuth0(); const onPress = async () => { try { await authorize(); } catch (e) { console.log(e); } }; return <Button onPress={onPress} title="Log in" /> }

Sedan brukar man även ha roller/behörigheter på plats, så att man kan ha t.ex. "Administratör" eller "Vanlig användare" och sedan checkar man av dessa permissions både i front-/backend för att låsa ned/dölja viss funktionalitet.

Tjo! Tack så mycket för svaret!

Koden nedan för Login.tsx körs när du har klickat på "Logga in" och hela inmatningsvalideringen på klientsidan har godkänts (inmatade fält i rätt format som e-post och lösenord i detta fall):

// If we are here, then we can attempt to log in by using a fetch POST request const loginPayload = { username: email, password: password, method: "login", }; fetch(LOGIN.URL, { method: "POST", headers: { Accept: "application/json", "Content-Type": "application/json", }, body: JSON.stringify(loginPayload), }) .then((response) => { if (response.ok) { let headerString = JSON.stringify(response.headers); // This will be changed and instead store unique random bytes based id value since cookie is sent with future requests headerString = headerString.slice(0, -3).split('set-cookie":"')[1]; AsyncStorage.setItem("user", headerString); // This will Redirect user to "MyRattmuffar" screen due to useContext() that setIsAuthenticated will trigger re-render setIsAuthenticated(true); } else { return response.json(); } }) .then((data) => { if (data) { setShowError(data?.error || "Något gick fel. Försök igen."); } }) .catch((error) => { setShowError("Något gick fel. Försök igen."); }); };

Bortse missen att det inte ännu är med async och await. Inuti exakt samma komponent finns en hook i början där sedan en useEffect() finns längre ned vilket då upptäcker att personen är inloggad eftersom isAuthenticated är nu sann:

const { isAuthenticated, isLoading, user, setIsAuthenticated } = useAuthContext(); useEffect(() => { if (!isLoading && isAuthenticated) { router.replace("/auth/my_rattmuffar/auth_myrattmuffar"); } }, [isAuthenticated, isLoading]); if (isLoading) { return null; }

Det hela fungerar, men jag hade önskat att det hela kunde ske på Router- & <Stack/>-nivå, dvs., när en skärm ska väljas. Jag ska ha sett någonstans där useContext() för autentisering ägde rum innan <Stack/> och sedan med en ternary där endast vissa skärmar visades vid ej inloggad annars visas andra autentiserade skärmar som bara går att komma åt vid godkänd autentisering.

Jag tänker middleware-aktigt likt i föråldrade ExpressJS där vid varje inkommen HTTPS-förfrågan så kontrolleras först om inloggningskaka finns och sedan om den har utgått på serversidan eller ej och sedan går du vidare till att behandla resten av förfrågan om den fortfarande anses vara giltig.

Det är lite klurigt med asynkrona som är useEffect() och hur den då vill köra om komponenten när något via useContext() uppdateras och sedan vill hinna rendera något innan useEffect() får säga sitt om router.replace(). Här undrar jag om useLayoutEffect() hade varit värt att fundera över även om jag läst i Reacts officiella dokumentering att det helst ska undvikas till varje pris på grund av prestandarisker.🤔

Vad som händer just nu är att det är en viss kortvarig "flickering" i det hela pga. att den vill visa något medan den kör sin långsamma useEffect(). Frågan är hur stor utsträckning av faktiska slutanvändare skulle störa sig på detta eller inte.

Min önskan är att få till det som att du klickar på "Logga in" och när den egentligen laddar in samma sida under tiden det asynkront körs i bakgrunden så ska inloggningsknappen ändras, fälten inaktiveras och så ser du en roterande laddningsikon så upplevelsen känns mindre "flickering".

Mvh,
WKF.

Visa signatur

(V)ulnerabilities
(I)n
(B)asically
(E)verything
Programming

Permalänk

Webbutvecklingsdagbok - efter studierna

[Jobb & Uppdrag
Möjligen kommer det lite jobb imorgon eftermiddag från Stockholmskunden. Annars inget nytt från övriga Uppdragsgivare.

Hobbyprojekt
Vänligen ta en titt på denna skönhet eller hemskhet vare sig du använder React Native Expo eller inte:

import { Text, Button, Alert, Image, TextInput, View, SafeAreaView, Pressable, ScrollView, StyleSheet, } from "react-native"; import React from "react"; import useDynamicStyles from "@assets/styles/styles"; import { useEffect, useState } from "react"; import { StatusBar } from "expo-status-bar"; import { Link, useRouter, Stack, useGlobalSearchParams } from "expo-router"; import { useAuthContext } from "@contexts/AuthContext"; import { FIND_RATTMUFFAR } from "@constants/crud-constants"; import { buildGraphQuery } from "@utils/QLBuilder"; import { useTranslation } from "react-i18next"; import BackBtn from "@components/buttons/BackBtn"; import { LINKS } from "@constants/link-constants"; import { CameraView, CameraType, useCameraPermissions } from "expo-camera"; const ScanRattmuffar = () => { const s = useDynamicStyles(); const { t } = useTranslation(); const router = useRouter(); const { isAuthenticated, isLoading, user } = useAuthContext(); useEffect(() => { if (!isLoading && !isAuthenticated) { router.replace(LINKS.LOGIN); } }, [isAuthenticated, isLoading]); const [permission, requestPermission] = useCameraPermissions(); const [scanned, setScanned] = useState(false); const [scannedData, setScannedData] = useState(""); return ( <> <SafeAreaView style={[s.container]}> <Stack.Screen options={{ headerShown: false }} /> <StatusBar style="auto" /> <View style={[s.flexRow, s.justifyBetweenRow, s.alignItemsCenter]}> <BackBtn href={LINKS.AUTH_MY_RATTMUFFAR} /> <Text style={[ s.marginTop48, s.MerriweatherBold, s.fontSize18, s.lineHeight21, s.colorPrimary800Const, { marginRight: 129 }, ]}> {t("scan_rattmuffar_heading_text1")} </Text> </View> {!permission?.granted && ( <View style={[s.containCenterXY, { flex: 1 }]}> <Text style={[ s.LatoBlack, s.Weight700, s.colorPrimary900Const, s.fontSize18, s.textCenter, s.lineHeight24, s.marginX16, s.marginBottom8, ]}> {t("scan_rattmuffar_permission_needed")} </Text> <Pressable style={[ { backgroundColor: s.colorPrimary900Const.color }, { padding: 20 }, { borderRadius: 50 }, { minWidth: 200 }, s.marginX16, ]} onPress={requestPermission}> <Text style={[ s.LatoBlack, s.Weight400, s.colorSecondary100Const, s.fontSize14, s.lineHeight20, s.textCenter, ]}> {t("scan_rattmuffar_grant_permission")} </Text> </Pressable> </View> )} {permission?.granted && scannedData.length != 13 && scannedData.length != 8 && ( <CameraView barcodeScannerSettings={{ barcodeTypes: ["ean13", "ean8"], }} onBarcodeScanned={({ data }) => { if (!scanned) { { setScanned(true); if (data.length !== 13 && data.length !== 8) { Alert.alert(t("scan_rattmuffar_invalid_barcode")); } else { setScannedData(data); } setTimeout(() => { setScanned(false); }, 3000); } } }} style={{ flex: 1 }} /> )} {(scannedData.length == 13 || scannedData.length == 8) && ( <View style={[s.containCenterXY, { flex: 1 }]}> <Text style={[ s.LatoBlack, s.Weight700, s.colorPrimary900Const, s.fontSize18, s.textCenter, s.lineHeight24, s.marginX16, s.marginBottom8, ]}> {t("scan_rattmuffar_valid_barcode")} {scannedData} </Text> <Pressable style={[ { backgroundColor: s.colorPrimary900Const.color }, { padding: 20 }, { borderRadius: 50 }, { minWidth: 200 }, s.marginX16, ]} onPress={() => { setScannedData(""); }}> <Text style={[ s.LatoBlack, s.Weight400, s.colorSecondary100Const, s.fontSize14, s.lineHeight20, s.textCenter, ]}> {t("scan_rattmuffar_scan_againBtn")} </Text> </Pressable> </View> )} </SafeAreaView> </> ); }; export default ScanRattmuffar;

Först har du klassisk vy med Tillbaka-knapp och skärmnamn (var du är någonstans i appen i princip). Sedan har du konditionerade retursatser beroende på om kameran har tillstånd att användas och/eller om det redan finns en EAN-kod som är 8 eller 13 siffror lång redan. Annars om kameran har tillstånd att användas så visas den.

När en EAN-kod hittas så undersöks den om den är 8 eller 13 tecken långt. Jag funderar på att även lägga till Regex för att säkerställa att alla tecken är siffror i stil med [i][/\d+/][i]. Om det är en giltig EAN-kod så visas en annan retursats vilket då gör att kamerakomponenten bör "nedmonteras". Just komponenters livscykler är klurigare i ReactJS än exempelvis VueJS tycker jag.

Det var delvis klurigt och frustrerande att försöka lista ut vad exakt jag behövde för just streckkodsinläsning med hjälp av

expo-camera-biblioteket då det är för omständligt att fixa Android SDK och XCode för att kunna använda react-native-vision-camera-biblioteket vilket kräver den utvecklingsmiljön lokalt. Så varsågod! Nu kan du kopiera min kamerakomponent om Du bara vill komma igång själv med att läsa in streckkoder utan att behöva fundera på av alla komponentattribut du egentligen behöver från CameraView-komponenten.

Jag har också blivit färdig med delarna som:
- Visar alla nuvarande rattmuffar.
- Visar enskild rattmuff genom att trycka på en av rattmuffarna från den nuvarande listan.

Nästa steg är nu att lägga till sökfunktionalitet och här kommer en ny React Hook jag har kikat lite på: useDeferredValue vilket verkar syfta på att fungera lite som en förenklad version av debounce för att fördröja till exempel när du matar in i ett inmatningsfält så att den inte reagerar direkt på första tecknet utan när du skrivit färdigt istället?🤔

Enligt Senioren så ska det inte vara några problem med att ha ett par tusentals "rattmuffar" som bearbetas direkt av klienten innan det hela bör ske på serversidan. Nuvarande webbhotell för NodeJS-baserade VPS-servern är Hetzner som fortfarande Senioren står bakom och inte Idéägaren. Personligen tycker jag att Idéägaren skulle stått bakom den så att de äger de data som finns vilket är enbart cirka tio rattmuffar i form av testdata.

Senioren sade idag att i veckan kommer att den nya databasmodellen att ha implementerats medan senast commit i själva serverkoden - vilket Senioren står/"ansvarar" för - är cirka tre veckor gammal. Det är en balansgång att fundera på hur mycket som är "lathet" och hur mycket som är "detta är obetalt hobbyprojekt och jag har saker att göra som faktiskt försörjer mig och min familj att prioritera först".🤔

Det ska väl tilläggas: Jag är Ensam Ungkarl™(?) medan Senioren är farsa så det säger nog också en hel del om den upplevda tiden som går att lägga på saker och ting här i vardagen! Jag sade "ansvarar" för det hela är ett valfritt hobbyprojekt och det finns som många gånger tidigare sagt var inga obligatoriska åtaganden från någon deltagare vilket gör det hela väldigt dynamiskt flyktigt med en gnutta turbulens ovanpå!

Någon frågade mig personligen på Discord om jag har några andelar i bolaget ännu. Inte ännu. Det återstå att se. Finns det appar som kan upptäcka "räkmacksåkare"?😬

Avslutningsvis kanske Du ser att jag har börjat refaktoriserat ut lite här och var i stil med KONSTANTER för exempelvis länkar, bilder, ikoner, vanligt använda komponenter, översättningsreferenser, och så vidare. Tack vare att jag äntligen(!) fick till något så banalt som Path Aliases så kunde jag flytta om filer och ordna det snyggt så det enligt vissa YT-klipp "ser ut som en Senior har satt upp kodprojektet".

(Detta är en minidetalj: ibland stör jag mig på att vissa så kallade 'CodeTubers' verkar insinuera - eller lider de bara av elitism inom programmering(?) - att juniorer är minst sagt lika dåliga/bra som de som nyss börjat lära sig programmera på helt egen hand...)

Vidareutbildning
Den delvis "onödiga" vidareutbildningen av React Native Expo fortsätter. Jag säger delvis "onödig" för det verkar vara mer för "proof-of-concept"-projekt än snarare faktiska produktionsinriktade projekt.

Förhoppningsvis inom kort™ kommer jag att kunna börja lära mig produktionsbaserad kod som mångmiljardbolag är villiga att betala för. Elixir, Erlang och COBOL - snart kommer jag!🤣

På återseende!

Mvh,
WKF.
---------
✔️HT2022-VT2024 TWEUG Webbutvecklings-programmet 120hp (distans)

Visa signatur

(V)ulnerabilities
(I)n
(B)asically
(E)verything
Programming

Permalänk

Webbutvecklingsdagbok - efter studierna

Jobb & Uppdrag
Jag fick mejl idag från tidigare Uppdragsgivare om att ett Afterwork kommer att äga rum någon gång i början på nästa månad nere på stan vid samma ställe där jag tidigare har träffat Uppdragsgivaren öga mot öga under det tidigare uppdragets gång. En högprofilerad person kommer att delta via Zoom då denne hade ej möjlighet att delta i person vid tillfället.

Under denna AW kommer takeaway-käk att förtäras medan den tidigare Uppdragsgivaren berättar om framtidsplanerna, utsikterna för 2025 och eventuellt om mina möjligheter för framtida uppdrag hos just denna tidigare Uppdragsgivare.

Idag fick jag även lite jobb från Stockholmskunden men betydligt mindre jobb denna vecka än föregående vecka. Det finns viss risk för lite arbete denna såväl som nästa månad då de månaderna kan vara ont om arbete på grund av den kundens kunders jobb.

Hobbyprojekt
Idag hade jag ett Google Meet med Idéägaren i hobbyprojektet jag är med i. Nu tog jag upp mitt delvisa "missnöje" mot Seniorens upplevda ambitionsnivå, det vill säga inte Senioren som person utan bara dennes ambitionsnivå utifrån mina egna upplevelser. Samtidigt poängterade jag förståelsen att inga i hobbyprojektet har några obligatoriska åtaganden så visst går det att uppleva missnöje men det finns inga reella så kallade "påtryckningsmedel" här.

Eventuellt "påtryckningsmedel" jag föreslog till Idéägaren är att ju fortare den nya databasmodellen förverkligas i serverkodbasen, desto tidigare går det även för Idéägaren att börja mata in diverse data om utifrån inlästa EAN-streckkoder om diverse "rattmuffar" tack vare att en backoffice har också implementerats där.

Den mycket goda nyheten nu är att Idéägaren har fixat egen server hos Hetzner och kommer att få det överfört vilket möjliggör att jag kan gå in och ändra direkt i serverkoden vid behov, exempelvis om jag behöver möjliggöra för viss CRUD-anrop för att komma framåt med mobilappen. Ja, detta innebär också enormt ansvar så att inte allt förstörs och jag råkar gå på semester!

Idéägaren berättade även om framtidsplanerna för denna mobilapp och när det väntas kunna dra in pengar. Först och främst så berättade Idéägaren att det numera är ett bolag, ett dotterbolag till sitt konsultbolag, alltså mobilappen, typ "Rattmuffsappen AB". Vidare så kommer Idéägaren att äga bolaget till 100 %, inte ens dennes sambo kommer att få bli delägare ännu.

Det sistnämnda låter värre i ord än vad det faktiskt nödvändigtvis behöver vara. Å ena sidan så skulle jag kunna ta appen och göra eget men jag sa också under mötet idag att jag besitter ändå inte tillräckliga kunskaper i marknadsföring eller det värde som mobilappen kommer att tillföra inom området. Med andra ord är jag ingen "rattmuffsexpert".

Dessutom som jag tidigare sagt så skulle det enbart reflektera negativt för mitt personliga varumärke och jag är ju redan självutnämnd WebbKodsGnällare™ och det borde räcka nog!😂 Hur det än må gå med den mobila appen vid så kallad "test flight med early birds" och senare en skarp lansering så kommer jag ändå att ha lärt mig en hel del med att arbeta i grupp, om än på distans, vissa delar React-utvecklingsmiljön, och så vidare!🫡

Vidareutbildning
Jag fortsätter den fluktuerade utbildningsresan av React Native Expo via den mobila appen i Hobbyprojektet.

På återseende!

Mvh,
WKF.
---------
✔️HT2022-VT2024 TWEUG Webbutvecklings-programmet 120hp (distans)

Visa signatur

(V)ulnerabilities
(I)n
(B)asically
(E)verything
Programming

Permalänk

Webbutvecklingsdagbok - efter studierna

Jobb & Uppdrag
Det blir spännande någon gång i december i år när jag ska på AW hos en tidigare Uppdragsgivare i hopp om framtida uppdrag med dess numera patenterade varumärke. Jag har ju lärt mig riktiga "nybörjargrunder" inom mobilapps-utveckling vilket tar mig till...

Hobbyprojekt
... den stora "nyheten" att jag har "bugat, bockat och tackat för mig" i det frivilliga Hobbyprojektet som varade cirka sju veckor då det var den 25:e eller 26:e september 2024 som jag kom med i det frivilliga Hobbyprojektets Slack. Det finns en separat tråd om "avhoppet".

Vidare efterforskningar jag gjorde i samband med detta så visar det sig att Projektägaren tog ut runt 300 KSEK i aktieutdelningar från sitt huvudsakliga konsultbolag under åren 2023 och 2022. Med en vinst - vilket jag förmodar är efter utbetald egen lön som anställd i sitt egna bolag - på nästan 600 KSEK från 2023 så bör Projektägaren ha haft investeringsmedel tillgängligt.

En person jag brukar prata i telefon med brukar säga att, "Om någon inte är villig att betala för en idé eller sitt företag, vad säger det om hur mycket personen egentligen värderar denna idé eller sitt företag?" Möjligen var/är det något åt detta håll i detta frivilliga Hobbyprojekt jag var tillfälligt delaktig i.

Med det sagt så anser jag ändå att Projektägaren ifråga (och jag skrev också detta personligen till Projektägaren) är en ambitiös och driven person som förr eller senare kommer att lyckas lansera en konkurrenskrossande mobilapp inom den fritidsintressebaserade marknaden mobilappen ifråga siktar på.

Ett relevant framtida kodprojekt för mig nu är en "side-loadad träningsapp exklusivt för Android" som är just på det sätt jag vill att det ska vara. Träningsappar finns det överskott på men inte exakt som jag vill att den ska vara.

Relevant till det kommande kodprojektet är att en sak jag inte lärt mig ännu i mobila appar är dessa så kallade Push Notifications som du kan få vilket då syns även när mobilen är låst. Exempelvis skulle jag vilja få sånt med vibration påslaget efter vilotiden utgått mellan sets under pågående gympass, alternativt att ljud spelas till mina trådlösa lurar trots att musik spelas.

Viktig lärdom från dessa sju veckor i f.d. frivilligt kommersiellfokuserat hobbyprojekt:
- Arbeta aldrig gratis i uppenbara kommersiella projekt om det inte finns ett rimligt påskrivet ersättningsavtal innan.

Vidareutbildning
Vad ska jag göra nu? Jo, ta helg för en gångs skull för bövelen!

På återseende!

Mvh,
WKF.
---------
✔️HT2022-VT2024 TWEUG Webbutvecklings-programmet 120hp (distans)

Visa signatur

(V)ulnerabilities
(I)n
(B)asically
(E)verything
Programming

Permalänk

Webbutvecklingsdagbok - efter studierna

Jobb & Uppdrag
Jag kontaktade idag min tidigare och förhoppningsvis framtida Uppdragsgivare och frågade om jag kunde använda honom som en relevant referens i ett nytt uppdrag jag tänkte söka. Det sistnämnda berör databaser och SQL där färst två års erfarenhet "krävs" så jag skrev ihop ett PDF-CV för just det via Canva. Sedan mejlade jag det till relevant e-postadress med kontaktuppgifter samt den vänliga uppmaningen om snabb återkoppling från rekryterarens sida. Uppdragstipset kommer från en person från en Discord-grupp.

I PDF-CV:t hopsnickrat på Canva framgår det dock klart och tydligt - och högst troligt till min allra största nackdel - att min första "Arbetslivserfarenhet" är examensarbetet för Uppdragsgivaren och sedan nästa arbetslivserfarenhet är Uppdraget från Uppdragsgivaren. Detta betyder att rekryteraren bör kunna dra slutsatsen om att min nivå egentligen är junior och långt(?) ifrån senior. Vad som kanske "imponerar" är att i båda fallen tog jag i princip fram ett mycket simpelt CRM-system från grunden åt exjobb- och numera Uppdragsgivaren. (eller så kommer rekryteraren tycka att jag är knäpp som inte använt ramverk som alla andra!😂)

Därmed utgår från 99 % sannolikhet att jag ej går vidare i processen vilket betyder att 1 % sannolikhet skulle innebära en otroligt positiv överraskning i bästa fall. I rollen lär jag "slåss" mot diverse arbetslösa seniorer även om den titeln i sig egentligen inte säger någonting då det finns "seniorer" som fortfarande inte kan skriva en for-loop (enligt vissa Discord-rykten).

Frågan hos alla som varit länge hos företag och/eller uppdragsgivare är: "Varför är du fortfarande kvar här? Kontakter och/eller färdigheter främst?" Sedan har vi det här med intervjuprocessen och eventuella tester. Själv är jag mer av filosofin att, "Ge mig en vecka så kommer jag antingen ha kunna suttit mig tillräckligt in i det jag ska göra eller så inte."

Testerna kan ju vara missvisande på grund av den kognitiva nedsättningen som kan orsakas av stressen orsakat av den upplevda pressen med flertalet ögon skarpt riktade mot ens kodknackande. Rollen är tänkt att fungera på distans vilket skulle passa mig helt utmärkt. Nu när jag fått ett svenskt CV skrivet så ska jag även skriva ihop en engelsk version av den för att återanvända mot den internationella marknaden.

På tal om det sistnämnda så kommer vi in på ett intressant koncept gällande marknadsföring och mobilappar i och med det vinstdrivande projekt jag lämnade när jag insåg att jag inte längre respekterade min egen tid. Mobilappen jag lämnade så gjorde jag några efterforskningar kring dess marknad och jag upptäckte att det finns redan ett par svenska mobilappar som mer eller mindre erbjuder det denna var tänkt att erbjuda om än kanske inte lika snyggt implementerade och/eller designmässigt proffsiga i sina utseenden.

Jag hittade en mobilapp som kostade rakt av 65 SEK vars bolag hade omsatt runt 90 KSEK förra året och fjolåret. Detta är ju oerhört lite och då har vi inte ens räknat in den andel appaffären tar för varje 65 SEK. Här är nu det paradoxala med internationella marknader - spekulerar jag - å ena sidan har du en större marknad men också fler konkurrenter vilket gör att det kanske blir ännu svårare att slå igenom än lokalt. Möjligen kan genombrottet internationellt bli ännu större än lokalt om det väl lyckas slå igenom internationellt talat.

Gratisversionerna inom samma marknad av mobilappen jag utvecklade helt gratis i nästan sju veckors tid (cirka tre till fem dagar i veckan beroende på hur jag tog helg och mängden arbete från Stockholmskunden), hade i princip ännu lägre omsättning i bolagen bakom mobilapparna.

Med andra ord och sammanfattningsvis: Det såg väldigt dystert ut för denna mobilapp att kunna slå igenom. Och det finns en viktig sak gällande tid när du gör och/eller arbetar med något vilket kallas för Oppportunity Cost , det vill säga, "Vad kunde du ha gjort istället med samma tid spenderad?".

Samtidigt så var det inte helt bortkastad tid dessa sju veckors tid eftersom jag fick lära mig grunderna för plattformsöverskridande mobilappsutveckling via Expo (Go) och främst Development Build numera då flera saker försvinner i SDK52 för att pusha fler till att gå över att nyttja det på riktigt istället för att lattja runt i Expo Go-sandlådan.

(Inte lika mycket jobb denna vecka från Stockholmskunden men mer än noll i alla fall!🫡)

Hobbyprojekt
Vad gäller sandlådor såsom mina Hobbyprojekt så har jag funderat en del på en simpel träningsapp för min egen del. Om den ska ha en Unique Selling Point, för jag tänkte väl ta 20 SEK för den endast, så är det hur lätt den ska vara konfigurera för egna behov. Detta kommer främst ur egna upplevelser med andra mobilappar och fysisk aktivitet.

Det finns en mobilapp som jag använder för att ta långpromenader med. När den startas så kan du trycka direkt på en grön knapp för att börja spåra din promenad via GPS. När du är färdig däremot så kommer den först att visa dig reklam, sedan tre rutor om du vill spara det du gjorde, om du vill ladda upp till sociala och sedan en sammanfattningsskärm. Efter det så måste du trycka bakåt en gång och bekräfta för att stänga appen. Så oerhört irriterande i denna första värld jag lever i - att jag inte kan välja hur den ska bete sig.

Jag hade föredragit att när jag är färdig och bara vill stänga av appen samt spårningsfunktionen känd som "Plats" / "Location" ("GPS") så hade det varit fantastiskt om appen lät en kunna konfigurera appen att just jag vill att när jag är färdig med promenaden så ska den spara lokalt, stänga ned sig och även stänga "Plats" även om det skulle kräva bekräftelse från mig. (Jag vet inte om det krävs bekräftad behörighet att få slå av "Plats" om den redan är påslagen)

Sådan funktionalitet vill jag erbjuda i alla mina mobilappar: Möjligheten att kunna konfigurera den så att den blir tidseffektiv för den som använder den i den mån användaren önskar den att vara det för dem personligen. Så träningsappen kanske vissa vill posta direkt på sociala medier på grund av bekräftelsebehov att, "Nu ska jag börja gymma!" medan andra kanske vill att träningsappen först bara ska starta träning utan bekräftelsebehov. Välj det som passar dig.

Sedan fortsatte latheten inom mig att växa: Tänk om du kunde konfigurera om du vill så att när du startar appen så aktiverar den "Plats" och när du anländer till just där du tränar så startar den igång träningssession för att du har markerat på kartor vart den ska starta igång session? Då har du ytterligare mer automatik och viktigaste utav allt: Om du vill så går det att konfigurera, aldrig ett krav!

Det är bristen på att kunna konfigurera som får mig att kräkas upp magsyra till och från!🤣

Vidareutbildning
Nästa steg nu blir att lära sig Expo Development Build lokalt med Android SDK-emulator(?) eller vad det nu heter. En "renoverad" iPhone hade nog också varit på sin plats som en framtida investering för att kunna göra mobilappen riktigt plattformsöverskridande om jag ändå tänker sälja den för hela tjugo spänn vid ett senare tillfälle?🤔

(Ja, just det! Jag måste ju också ansöka om att få bli utvecklare i Play respektive App Store!🤦‍♂️)

På återseende!

Mvh,
WKF.
---------
✔️HT2022-VT2024 TWEUG Webbutvecklings-programmet 120hp (distans)

Visa signatur

(V)ulnerabilities
(I)n
(B)asically
(E)verything
Programming

Permalänk

Webbutvecklingsdagbok - efter studierna

Jobb & Uppdrag
Om drygt en timme ska jag på "Afterwork" hos tidigare Uppdragsgivare och försöka sälja in en faktisk mobilapps-version av det som annars är en webbapps-version av det tidigare åtta veckors genomförda uppdrag jag genomförde åt Uppdragsgivaren vilket Uppdragsgivaren blev mycket nöjd över.

Sannolikheten för nytt uppdrag inom en mycket snar framtid är dock lågt då Uppdragsgivaren själv har haft utmaningar med att hitta slutkunder till mjukvaran jag har tagit fram åt dem. En högprofilerad samarbetspartner kommer även att närvara via Zoom eller Teams vilket också kommer att få prova på webbappen. Möjligen kan jag sälja in mig hos den högprofilerade personen?🤔

Gällande Jobb och Uppdrag så är jag i den "rävsaxiga" situationen när det gäller att hitta nya Webbutvecklingsrelaterade konsultuppdrag att :

1) Jag är nyutexaminerad Full-stack Junior-webbutvecklare så min erfarenhet bör klassas som 0 trots mina slutbetyg och exjobbet vilket också ledde till ett åtta veckors uppdrag.

2) För att få arbetslivserfarenhet så behövs jobb och för jobb så behövs arbetslivserfarenhet och nu sätter vi "visited" på båda dessa noders kanter!🤣

Jag har en Stockholmskund där arvodet är 237 SEK exkl. moms/rapporterad timme och sedan kan slutkunden göra en rimlighetsbedömning och antingen bestrida faktura eller godkänna den. Här är utmaningen att jag är ett av många led där det jag gör har en direkt påverkan på hur mycket efterarbete övriga led måste göra, alternativt får jag reklamation (=åtgärda i efterhand utan arvode).

Frågan är då om jag bör göra anspråk på högre arvode (det finns inget påskrivet avtal dock) i och med att arbetet jag gör är mentalt krävande (inte komplicerat men krävande då det tar tid att kvalitetssäkra innan leverans - och tid är ju pengar som vi alla vet) samtidigt som det jag gör bör ju vara tillräckligt värdefullt för dem att det då ska vara värt den tid det tar? Arbetet jag gör går att räkna på antal korrekt(!) skrivna HTML-rader per minut så det finns även en kostnadseffektivitetsaspekt att betrakta i det hela (en gnutta kryddning av Taylorism).

"Desperat situation kräver desperat åtgärd" - Nu kan följande låta motsägelsefullt i och med min tidigare erfarenhet med att arbeta gratis åt ett numera uppstartat AB: I och med min brist på arbetslivserfarenhet så skulle det ju kunna gå att göra som så att jag arbetar mellan en-två arbetsveckors tid hos något faktiskt AB som sedan måste lämna en positiv referens förutsatt att de är nöjda och/eller anlita mig tills vidare som Uppdragstagare.

Min tanke i början är att få AB kommer vilja anlita mig direkt som Uppdragstagare men möjligen låta mig - under sekretessavtal såklart - få kanske fixa små QoL-grejer hos dem internt i den rimliga utsträckning det går på endast en-två arbetsveckor. Då kan jag i bästa fall få ett kortvarigt nytt Uppdrag och/eller en positiv referens att söka faktiska Uppdrag med.

Nu kanske Du tänker att jag då bara gör samma misstag igen: arbetar gratis. Det skulle stämma. Samtidigt går det att betrakta utifrån faktumet att även om jag gör egna hobbyprojekt så finns det ingen Uppdragsgivare som kan ge mig en positiv referens kring det jämfört med om jag gjorde något enklare/kortare gratis åt något AB.

Och vill inte AB:t ifråga lämna någon positiv referens efter det gratis arbete jag har gjort så har jag troligen "dodget a bullet" i samma veva med antagelsen att det jag gjorde faktiskt objektivt talat var/är "good enough". Det hela kan ju ses ett kontroversiellt sätt att ge ett "smakprov" till AB i utbyte att om de faktiskt var/är nöjda med det så kan de bjussa på ett begränsat tekniskt utlåtande/referens om det jag har gjort åt/hjälpt dem med.

"Varför inte bara använda nuvarande Uppdragsgivare?" - Tillåt mig få besvara den funderingen!
En utmaning med nuvarande Uppdragsgivare är att denne inte är tillräckligt IT-insatt för att kunna ge ett tekniskt utlåtande om mina kodkunskaper och/eller -förmågor (precis som denne ej är någon läkare att lämna ett medicinskt utlåtande om min biologiska hälsa). Denne kan - än så länge - endast ge ett utlåtande om helhetsupplevelsen och hur samarbetsupplevelsen var med mig vilket var/är mycket positiv enligt Uppdragsgivaren.

En annan sak jag funderat på att prova nu är att spela in ett slags "Video-CV" där jag berättar om den faktiska Uppdragsgivare jag har haft och sedan visar något - med skriftligt tillstånd såklart - jag har gjort och på så vis komma förbi allt textbaserat CV-trams. I slutändan handlar det ju ändå om endast två saker:

1) Dokumenterade tidigare tillfredsställande slutförda projekt-/uppdragsresultat
2) Nuvarande goda upprätthållna nätverks-/referenskontakter att kunna hänvisa till

Så länka till någon YT och såklart säga ("Ja, kontrollera länken innan du klickar på den!"😅).

Vid tillfälle så får Du gärna besvara i tråden om Du har några andra tips & trix om ovanliga sätt att söka IT-uppdrag på utöver att skicka in intetsägande CV!😎

(Psst! Någon i Slack-gruppen där jag är med sa att vissa anser att CV idag är så passé?!😱)

Hobbyprojekt
Under december 2024 så har jag deltagit i min tidigare panikångestinducerande "fiende" Advent of Code 2024. Denna gång så gjorde jag något jag själv kallar för "kommentarskoda" vilket betyder att jag skriver en kommentar i ett givet programmeringsspråk så att nästa rader efter kommentaren blir koder utifrån kommentaren. I princip "kommentarspromptar" jag.

Sedan LLM:ers intåg så var jag försiktig med dem redan under andra halvåret som blivande Full-Stack Junior-Webbutvecklare och jag använde endast kodförslag som jag faktiskt själv kunde förstå både i dess mikro- såväl som makroskopiska sammanhang. Så att be om fullständiga lösningar har jag aldrig förväntat mig och därmed aldrig provat mig på och jag förstår ärligt talat inte de som förväntar sig detta oavsett hur mycket marknadsjippo som används av LLM-bolagen.

Jag skriver en kommentar i taget för att göra/lösa en sak i taget och då ansvarar jag för algoritmen (=kodstegen) som tas fram även om vissa detaljer kanske lämnas åt LLM:en. Sedan kanske jag inte alltid blir nöjd med vissa detaljer. Då som tur var - då jag än så länge faktiskt fortfarande kan läsa kod - kan jag ändra detaljerna så att övriga kodsteg blir logiska och även i det stora hela då jag varit med i alla kodsteg och därmed kan se i det stora hela.

Då kan jag även betrakta säkerhetsaspekter t.ex. inmatningssanering, inmatningsvalidering, inmatningsinjektioner, med mera, vilket går att lägga in manuellt för jag förväntar mig inte att all träningsdata hos LLM:erna "automatiskt" ska ha detta i åtanke. Visst skulle man kunna ha med det i standardprompten men det känns bättre att jag manuellt har lagt in det så att jag också kan minnas att jag har gjort det i efterhand än att gissa mig fram om LLM:en hade gjort det eller ej vilket blir riskfylldare i takt med växande kodbas.

Vidareutbildning
I och med AoC 2024 där jag lyckades vara med i ungefär sju hela dagar (både del 1 och 2) så blev det en viss utbildning i algoritmtänkande och jag kikade även på YT kring vanliga programmeringsmönster för algoritmskapande (dessa gällde dock för Leetcode men algoritmer är ju algoritmer och går att anpassa och/eller extrapolera från).

Jag har också en hel del att fixa nu i och med kommande Julfirande och andra sociala åtaganden så här vid kommande Nyårstider och så vidare...

På återseende!

Mvh,
WKF.
---------
✔️HT2022-VT2024 TWEUG Webbutvecklings-programmet 120hp (distans)

Visa signatur

(V)ulnerabilities
(I)n
(B)asically
(E)verything
Programming

Permalänk
Medlem

Följer dig med spänning WKF, hoppas det går bra! Får man fråga varför du inte tar anställning och kör företaget på sidan tills du har införskaffat dig mer erfarenhet? alt går in som underkonsult? Combitech,afry m.fl har partnernätverk där de söker underkonsulter till uppdrag de har vunnit.

Som konsult själv så ser jag och svara på alla dessa anbud, nivå 3 - nivå 5 (3-4+ års erfarenhet, 3-4 olika referensuppdrag m.m) verkar vara minstanivå.

Är du inne och kollar hos konsultmäklarna? Ework, Magnit?

Visa signatur

2008: I5 - 550w corsair - 2x2g corsair x-treme - Asus P7P55D LE - Xfx 5850 - w7 64.

2023: I5 -13600k - 1000w rme- 2x16gb ddr5 5200mhz - X670E-A - 3070

Permalänk
Skrivet av Palmen16:

Följer dig med spänning WKF, hoppas det går bra! Får man fråga varför du inte tar anställning och kör företaget på sidan tills du har införskaffat dig mer erfarenhet? alt går in som underkonsult? Combitech,afry m.fl har partnernätverk där de söker underkonsulter till uppdrag de har vunnit.

Som konsult själv så ser jag och svara på alla dessa anbud, nivå 3 - nivå 5 (3-4+ års erfarenhet, 3-4 olika referensuppdrag m.m) verkar vara minstanivå.

Är du inne och kollar hos konsultmäklarna? Ework, Magnit?

Tjo, tack så mycket för ditt svar!

Det där med anställning leder ju igen till den där rävsaxen: Vem vill anställa oerfarna (=juniorer) och hur får man erfarenhet utan att bli anställd först? Därför jag anser att anlitad som (under)konsult så utgör jag inte de riskerna en anställning kan innebära för företaget ifråga om vi tittar från företagets håll.

Menas "underkonsult" att det då finns ett ytterligare led mellan mig och slutkunden, dvs., konsultbolaget som sitter på uppdraget? Jag antar då att detta ytterligare led innebär lägre arvode till underkonsulter än om man vore direktkonsult i och med kakan som ska has i det mellersta ledet? 🤔

Mvh,
WKF.

Visa signatur

(V)ulnerabilities
(I)n
(B)asically
(E)verything
Programming

Permalänk
Medlem
Skrivet av WebbkodsFrilansaren:

Tjo, tack så mycket för ditt svar!

Det där med anställning leder ju igen till den där rävsaxen: Vem vill anställa oerfarna (=juniorer) och hur får man erfarenhet utan att bli anställd först? Därför jag anser att anlitad som (under)konsult så utgör jag inte de riskerna en anställning kan innebära för företaget ifråga om vi tittar från företagets håll.

Menas "underkonsult" att det då finns ett ytterligare led mellan mig och slutkunden, dvs., konsultbolaget som sitter på uppdraget? Jag antar då att detta ytterligare led innebär lägre arvode till underkonsulter än om man vore direktkonsult i och med kakan som ska has i det mellersta ledet? 🤔

Mvh,
WKF.

Saker är inte så svart och vitt som du tänker, stora konsultföretag sitter på stora ramavtal och kundkontakt där de har möjlighet att sälja in juniora positioner. Just nu är det ju lite svårare att få in juniora men med tanke på din ambitionsnivå och egna intresse bör du ändå ha en större chans. En stor projektrisk som ensamföretagare är att blir du sjuk/annat som gör att du inte kan leverera, ansvarsförsäkringar? Hur hanterar du kunddata? Där har ju företag en fördel med redundans på personal, juridikavdelning m.m. Du utgör mer risker lol

Ja precis. Men som du själv identiferiar, behöver du ju börja någonstans, få in referensuppdrag och erfarenhet.

Visa signatur

2008: I5 - 550w corsair - 2x2g corsair x-treme - Asus P7P55D LE - Xfx 5850 - w7 64.

2023: I5 -13600k - 1000w rme- 2x16gb ddr5 5200mhz - X670E-A - 3070

Permalänk
Medlem

Har du försökt att söka några jobb?

Alla är juniora någon gång i livet - därför måste juniora anställas för att vi faktiskt ska ha kompetent arbetskraft framöver. Ingen av de jag studerade med (eller jag heller för den delen) hade några som helst problem att få jobb efter examen.

På mitt nuvarande jobb tar vi in en del konsulter - det har blivit många juniora då de är brist på seniora.

Finns inga direkta risker med att ta in juniora. Det är initialt 6 månader provanställning - så om du är helt inkompetent/svår att arbeta med så kan man ju alltid säga upp den utan någon direkt orsak och då har man max betalat ut 6 månader av juniorlön. Alternativt så har man hittat sig en lovande utvecklare.

Tycker personligen du gör ett misstag som börjar ditt yrkesliv som egenföretagare. Man lär sig fruktansvärt mycket i ett företag då du omges av andra kompetenta utvecklare - de kommer ha större vilja att agera mentorer och ta dig under sina vingar om du faktiskt är deras anställda.

Du tror inte att du bara hittar på bortförklaringar för dig själv i att inte bli anställd p.g.a att du vill jobba remote...?

Visa signatur

10700K | NVIDIA RTX 3080

Permalänk
Medlem
Skrivet av WebbkodsFrilansaren:

Det där med anställning leder ju igen till den där rävsaxen: Vem vill anställa oerfarna (=juniorer) och hur får man erfarenhet utan att bli anställd först? Därför jag anser att anlitad som (under)konsult så utgör jag inte de riskerna en anställning kan innebära för företaget ifråga om vi tittar från företagets håll.

Tipsar om att det finns konsultbolag(känner till åtminstone 1) i ditt område som tar in helt juniora/nyexade på betalt trainee-program(12v?) och sen ut till kund.