Kirjautuminen

Haku

Tehtävät

Keskustelu: Ohjelmointikysymykset: JavaScript: React ja TextInput hidden?

Sivun loppuun

walkout_ [18.03.2023 10:10:10]

#

Hei,

Miten jos haluan hidden lomakekentän React:sa niin miten saan siihen velue:n niin, että lomakkeen validointi menee läpi?

Eli tässä koodia:

<div className="form-group text-left">
   <TextInput
      label={"Domain"}
      value="www.domain.com"
      name="domain"
      hidden="true"
    />
</div>

Eli tuo value ei tule hidden tyyppiseen kenttään olenkaan ja on ihan sama mikä domain siinä on.

walkout_ [19.03.2023 08:43:58]

#

Ei onnistu edes näin vaan TextInput-kentään ei tule veluea edes jos kenttä ei ole piiloitettu.

<div className="form-group text-left">
   <input value="www.domain.com" name="domain" hidden="true" />
</div>

Eli yllä olevalla koodilla velue kyllä tulee kentään automaatisesti muttei mene domain validoinnista läpi, koska validointi ei tunnista name="domain"-atribuutia.

Tässsä React.js validointikoodia alla:

const SignupSchema = Yup.object().shape({
    name: Yup.string().required("Required").max(32, "Too Long!"),
    email: Yup.string()
      .email("Invalid email")
      .required("Required")
      .max(64, "Too Long!"),
    domain: Yup.string()
      .matches(/([a-z0-9]+\.)*[a-z0-9]+\.[a-z]+/, "Domain is invalid")
      .required("Required"),
    password: Yup.string()
      .required("Required")
      .min(8, "Too Short!")
      .max(32, "Too Long!"),
    confirmPassword: Yup.string()
      .required("Required")
      .oneOf(
        [Yup.ref("password"), null],
        "Password and Confirm password should be same."
      ),
});

Lebe80 [20.03.2023 15:33:44]

#

Onko tuo (hidden="true" oikea propsi, vai pitäisi olla html-input -kenttien mukaisesti type="hidden" ?

noutti [20.03.2023 15:53:44]

#

Mitä formikirjastoa käytät? Ilmestyykö koko objekti onSubmitissa?

walkout_ [21.03.2023 12:34:01]

#

noutti kirjoitti:

Mitä formikirjastoa käytät? Ilmestyykö koko objekti onSubmitissa?

Ilmestyy onSubitissa joo. Ja kirjato on alempana.

https://formik.org/

Itseasiassa ks. kirjaston React Native: https://formik.org/docs/guides/react-native

noutti [23.03.2023 06:45:44]

#

siis domain ilmestyy myös onSubmitissa? Tällöin validaatiossa on virhe? Miksi muuten käytät hidden fieldiä ylipäätään?

walkout_ [23.03.2023 07:15:54]

#

noutti kirjoitti:

siis domain ilmestyy myös onSubmitissa? Tällöin validaatiossa on virhe? Miksi muuten käytät hidden fieldiä ylipäätään?

Ei vaan domain ei ilmesty ollekaan kentään alla ovelalla koodilla:

<TextInput
      label={"Domain"}
      value="www.domain.com"
      name="domain"
      hidden="true"
    />

Eli siksi ei toimi. Validoinnissa ei ole mitään vaikaa, koska kutenkin jos kenttä ei ole hidden ja sen täyttää manuaalisesti niin validointi menee läpi.

noutti [23.03.2023 12:26:20]

#

Snadisti hankala vastata, koska Formik kyllä ymmärtää oikein käytettynä myös hidden fieldit. Oletko siis hoitanut tuon TextInputin siten, että jollain statella toggletaan hiddeniä true tai falseksi?

Kentällä tarkoitat ilmeisesti objektia, joka tulee onSubmitissa mukana? Oletko rekisteröinyt kyseisen fieldin initialValueihin mukaan, vaikka on hidden? En muista ihan tarkasti miten formikissa tuo handlataan, mutta muistikuvieni perusteella ainakin typescriptillä työskennellessä initialvaluet tulee passata mukaan, jotta ei heitä herjaa.

Edit: https://stackoverflow.com/questions/53869048/reactjs-formik-hidden-field-sending-null-value-to-server

Metabolix [23.03.2023 12:27:53]

#

Sinulla pitäisi varmaan olla oikea piilotettu kenttä (<input type=hidden>) eikä muun kentän piilotus (hidden=true). Ensimmäinen tekee toimivan mutta näkymättömän kentän ja jälkimmäinen käytännössä poistaa kentän käytöstä Reactissa.

Jos kenttiä piilottaa muuten kuin tekemällä oikean piilokentän, yleensä silloin niiden arvojakaan ei lähetetä. Ainakin netissä sanotaan, että Reactissa hidden=true aiheuttaa juuri tämän ongelman. Monet ratkaisut tähän näyttävät olevan melkoista purkkaa (kuten noutti yllä linkittää) ja liittyvät ilmeisesti siihen, että kenttä joskus halutaan esiin ja joskus ei. Jos kenttä on aina piilossa, kannattaisi tehdä ihan oikea piilokenttä ilman muita kikkoja.

noutti [23.03.2023 12:29:58]

#

Metabolix kirjoitti:

Sinulla pitäisi varmaan olla type=hidden eikä hidden=true. Ensimmäinen tekee toimivan mutta näkymättömän kentän ja jälkimmäinen käytännössä poistaa kentän käytöstä Reactissa.

<TexInput/> on komponentti eikä natiivi elementti.

Edit: Nyt kun oikein katselen, niin todella vaikeaa debugata. Kun valuen tulisi olla value={values.domain} mikäli on formikin sisällä. Passaas koko formi ja logiikka, jota käytät. Ongelma ei ole pelkästään mikään hidden tason property

Metabolix [23.03.2023 12:51:17]

#

noutti kirjoitti:

<TexInput/> on komponentti eikä natiivi elementti.

Niin miksi siellä on TextInput, jos tavoitteena on oikeasti vain piilotettu input? Tästä varmaan kannattaisi ongelman ratkaisu aloittaa.

walkout_ [23.03.2023 19:22:32]

#

Metabolix kirjoitti:

noutti kirjoitti:

<TexInput/> on komponentti eikä natiivi elementti.

Niin miksi siellä on TextInput, jos tavoitteena on oikeasti vain piilotettu input? Tästä varmaan kannattaisi ongelman ratkaisu aloittaa.

Sikisi että rekisteroityymisessä on kaksi moodia, eli vain domain i4ware.fi sähköpostin omaava voi rekisteröityä ja sitten sellainen että kuka vaan voi rekisteritä omalla domainlila.

noutti [23.03.2023 19:47:19]

#

Metabolix kirjoitti:

noutti kirjoitti:

<TexInput/> on komponentti eikä natiivi elementti.

Niin miksi siellä on TextInput, jos tavoitteena on oikeasti vain piilotettu input? Tästä varmaan kannattaisi ongelman ratkaisu aloittaa.

Miksi siellä pitäisi olla piilotettu input, jos homman voisi hoitaa API:ssa? Mitä jos sillä TextInputilla on joku funktio?

walkout_ kirjoitti:

(23.03.2023 19:22:32): ”– –” Sikisi että rekis­te­roi­tyy­mi­sessä on kaksi...

Pystytkö passaamaan vaikka koko komponentin minimoidulla logiikalla tänne näin? Olisi helpompi katsoa. Sisällytä myös importit mikäli käytät kolmannen osapuolen kirjastoa. Mieleeni tuli myös sellainen, että mikäli visibility on hoidettu tyyliin näin komponentissa itsessään: visibility ? <input/> : null, niin tuolloin formikin eka rendaus saattaisi olla syypää. Toinen joka tulee mieleeni on se, että kyseiselle inputille ei ole annettu defaultValueta riippuen miten käytät formikkia. Hookkina vai wrapperina.

Ongelma ratkeaisi alta aikayksikön jos näkisi koodin.

walkout_ [31.03.2023 10:05:31]

#

Niin validointi ei toimi siis Front-endillä mutta PHP-back-end:in kanssa ei ole ongelmaa.

Mutta onko nyt hyvä laittaa tänne koko frontti-koodi, koska se sisältää 268-riviä koodia?

Grez [31.03.2023 11:39:32]

#

No tuossahan sanottiin että minimoitu versio.

walkout_ [31.03.2023 14:23:38]

#

Eli tässä frontin koodin alkua:

import React, {useEffect, useState} from "react";
import "./RegistrationForm.css";
import {API_BASE_URL} from "../../constants/apiConstants";
import {Redirect, withRouter} from "react-router-dom";
import {AuthContext} from "./../../contexts/auth.contexts";
import request from "../../utils/Request";
import {Field, Form, Formik} from "formik";
import * as Yup from "yup";
import TextInput, { PassWordInput } from "./../common/TextInput";
import Captcha from "demos-react-captcha";
import "./../../captcha.css";

const SignupSchema = Yup.object().shape({
    name: Yup.string().required("Required").max(32, "Too Long!"),
    email: Yup.string()
      .email("Invalid email")
      .required("Required")
      .max(64, "Too Long!"),
    domain: Yup.string()
      .matches(/([a-z0-9]+\.)*[a-z0-9]+\.[a-z]+/, "Domain is invalid")
      .required("Required"),
    password: Yup.string()
      .required("Required")
      .min(8, "Too Short!")
      .max(32, "Too Long!"),
    confirmPassword: Yup.string()
      .required("Required")
      .oneOf(
        [Yup.ref("password"), null],
        "Password and Confirm password should be same."
      ),
});

function RegistrationForm(props) {
  const [state, setState] = useState({
    name: "",
    email: "",
    domain: "",
    password: "",
    confirmPassword: "",
    successMessage: null,
  });
  const [error, setError] = useState(null);
  const [agree, setAgree] = useState(false);
  const [captchaSuccess, setCaptchaSuccess] = useState(false);

  const {authState, authActions} = React.useContext(AuthContext);
  const [setting, setSetting] = React.useState({
    show_captcha: false,
    disable_registertion_from_others: false
  });

Jonka jälkeen allaoleva koodi hakee lomakkeen asetukset:

useEffect(()=>{
    request()
      .get("/api/settings")
      .then(res => {
        if(res.status == 200 ){
            const obj = {};
            for (let i = 0; i < res.data.data.length; i++) {
                const element = res.data.data[i];
                if(element.setting_value == "1"){
                    obj[element.setting_key] = true
                }
                if(element.setting_value == "0"){
                    obj[element.setting_key] = false
                }
            }
            setSetting(obj);
        }

      })
  },[])

Ja tässä palautetta:

return (
  <div className="d-flex justify-content-center">
    <div className="card col-12 col-lg-6 login-card mt-2">
      <div
        className="alert alert-success mt-2"
        style={{display: state.successMessage ? "block" : "none"}}
        role="alert"
      >
        {state.successMessage}
      </div>
      <Formik
        initialValues={{
          name: "",
          email: "",
          domain: "",
          password: "",
          confirmPassword: "",
        }}
        validationSchema={SignupSchema}
        onSubmit={(values, formProps) => {
          if(agree == true){
            sendDetailsToServer(values, formProps);
          }
        }}
      >
        {({values, errors, submitCount}) => {

Ja TextInput:

{setting.disable_registertion_from_others &&
                <div className="form-group text-left">
                  <TextInput
                    label={"Domain"}
                    name="domain"
                  />
                  <small id="domainHelp" className="form-text text-muted">
                    You need to know right domain that is in use.
                  </small>
                </div>
                }

jlaire [31.03.2023 17:41:19]

#

Minimoinnin tarkoitus taitaa olla pikkuisen hukassa.

Löysin tällaisen sivun, jossa on neuvoja koodin jakoon, kun kysyy apua: https://stackoverflow.com/help/minimal-reproducible-example

Omalta osaltani voin sanoa, että jos kysymyksessä on mukana kokonainen esimerkki, jonka pystyn itse testaamaan, todennäköisesti yritän ratkaista ongelman. Koko viestiketju saattaa päättyä hyvin nopeasti muutamaan viestiin ja kaikki voivat jatkaa elämäänsä.

Ilman asiallista koodipätkää painan ctrl-w enkä ala tulkkaamaan vajaita koodipätkiä päässäni. Auttamiseen ei viitsi käyttää aikaa, jos kysymyksen esittäjä ei ole viitsinyt hoitaa omaa osuuttaan kunnolla.

Grez [31.03.2023 18:09:57]

#

Yleensä minimointi on hyvä harjoitus tehdä jo ennen kysymyksen lähettämistä foorumille. Joskus käy niin, että kun alkaa minimoida ongelmaa, niin keksii itse todellisen syyn, eikä tarvitse edes laittaa kysymystä.

walkout_ [31.03.2023 20:14:05]

#

Olen jo ratkaissut ongelman niin, että domain pitää täyttää niin, että pitää tietää oikea domain, joka on käytössä. Tämä lisää tietoturvaa ettei botit tee tunnuksia järjestemään.

noutti [04.04.2023 21:26:27]

#

No hyvä, että jollain metodilla sait fiksattua. Johtui todennäköisesti tuosta renderointitavasta.

Mikäli haluat rakentavaa palautetta koodista, niin voin tehdä muutamia huomioita. Jos et, niin hyvää kevättä!

walkout_ [06.04.2023 09:54:56]

#

noutti kirjoitti:

Mikäli haluat rakentavaa palautetta koodista, niin voin tehdä muutamia huomioita. Jos et, niin hyvää kevättä!

Rakentava paluste olisi koodista mielen kiintoista, koska olen ostanut sen Upwork-palvelun kautta Intialaiselta kevytyrittäjälä ja maksanut sille melken 2000 USD ja tehnyt sitten korjauksia tämän koodiin itse, koska en ole tilanut koko hoitoa täysin valmiina vaan ne osat joita en itse ole osannut tehdä kuten Laravel 9:n ja React:in välinen ACL. Sopimuksessa oli että itse korjaan vierheet jos tämän Intialaisen tuotokset eivät vasta sitä mitä haluan.

carabia [08.04.2023 04:55:57]

#

opetuksena tästä uloskävelylle: osta intiaa, saa intiaa

walkout_ [08.04.2023 15:58:55]

#

carabia kirjoitti:

opetuksena tästä uloskävelylle: osta intiaa, saa intiaa

Tämäpä tämä, sillä jouduin korjailemaan paljon ks. Intialaisen tekijän työtä.

walkout_ [08.04.2023 16:06:47]

#

Mutta mistä saisin kohtuuhintaisen Suomalaisen freelancerin, jolla on oma yritys ja voi laskuttaa minua?

muuskanuikku [11.04.2023 05:26:30]

#

walkout_ kirjoitti:

Mutta mistä saisin kohtuuhintaisen Suomalaisen freelancerin, jolla on oma yritys ja voi laskuttaa minua?

Haiskahtaa rasismilta. Intialaisuus ei tee kenestäkään huonoa koodaria eikä suomalaisuus hyvää. Minä tunnen useita huonoja suomalaisia koodareita; he ovat työkavereitani.

Osaavalle tekijälle maksetaan kansainvälisesti kilpailukykyistä palkkaa rodusta ja asuinpaikasta riippumatta. Halpaa koodaria etsivä joutuu tinkimään työn laadusta.

carabia [11.04.2023 12:12:17]

#

Tämä on rasismi Intiassakin puurot on koiranruokaa

carabia [11.04.2023 12:20:37]

#

Valuutta siis kannattaa vuotaa maasta ulos huippuosaavien halpojen intialaisten syliin, mielellään vielä ulkomaalaisten alustojen kautta, jotta hekin saavat osansa. Eiväthän hekään muutoin eläisi.

Vastenväittäminen on rasismia,ja aina kannattaa huomauttaa että onhan niitä kehnoja duunareita täälläkin. Onneksi snusmumrikenin poliittinen kompassikin saatiin samalla selvitettyä

walkout_ [11.04.2023 17:19:44]

#

Intialainen maksaa $20 / tunti ja Suomalainen vähintään 50 € / tunti + ALV 24 %.

Googlettamalla en lyödä yhdenmiehen tai naisen yrityksiä joiden hinta olisi 50 € / tunti + ALV 24 %.

Ja kyllä mä maksan mielellään ennemmän kuin $20 / tunti Suomalaiselle jos työn jälki on perempi ja pidetään kiinni siitä mitä on sovittu.

noutti [13.04.2023 13:27:30]

#

carabia kirjoitti:

(11.04.2023 12:20:37): Valuutta siis kannattaa vuotaa maasta ulos...

Kannattaa vetää se pää ulos perseestä välillä.

// Tässä importattu React kokonaisuudessaan ja mukaan vielä useEffect ja useState
import React, { useEffect, useState } from "react";
// Styled-components on hyvä tapa tehdä CSS:ää Reactissa
import "./RegistrationForm.css";
import { API_BASE_URL } from "../../constants/apiConstants";
import { Redirect, withRouter } from "react-router-dom";
// Jos tämä on auth, niin siirretään app.jsx:n mielummin, kuiten komponenttiin.
import { AuthContext } from "./../../contexts/auth.contexts";
import request from "../../utils/Request";
import { Field, Form, Formik } from "formik";
import * as Yup from "yup";
// ???
import TextInput, { PassWordInput } from "./../common/TextInput";
// Näitä ei kannata oikeasti pyörittää itse.
import Captcha from "demos-react-captcha";
import "./../../captcha.css";

/**
 * Projekteissa kannattaa eriyttää validaatiot erikseen, jotta niitä voidaan kutsua useissa eri paikoissa.
 * Tässä on käytetty Yuppia, joka on ihan pätevä, mutta itse käyttäisin zodia, koska sillä saa tyypitykset
 * kätevästi mukaan.
 */
const SignupSchema = Yup.object().shape({
  name: Yup.string().required("Required").max(32, "Too Long!"),
  email: Yup.string()
    .email("Invalid email")
    .required("Required")
    .max(64, "Too Long!"),
  domain: Yup.string()
    .matches(/([a-z0-9]+\.)*[a-z0-9]+\.[a-z]+/, "Domain is invalid")
    .required("Required"),
  password: Yup.string()
    .required("Required")
    .min(8, "Too Short!")
    .max(32, "Too Long!"),
  confirmPassword: Yup.string()
    .required("Required")
    .oneOf(
      [Yup.ref("password"), null],
      "Password and Confirm password should be same."
    ),
});

// export default function RegistrationForm. Komponenttiajattelussa jokainen tiedosto sisältää yhden komponentin, joten ei tarvita muita exportteja.
function RegistrationForm(props) {
  // Nimeämisessä mielummin formValues (itseasiassa tämä lienee defaultFormValues) ja setti setFormValues
  const [state, setState] = useState({
    name: "",
    email: "",
    domain: "",
    password: "",
    confirmPassword: "",
    successMessage: null,
  });
  // Tämä muuttuu myös turhaksi jos jaksat lukea loppuun...
  const [error, setError] = useState(null);
  // Miksi tämä ei ole statessa?
  const [agree, setAgree] = useState(false);
  // Tämäkin muuttuu turhaksi pian....
  const [captchaSuccess, setCaptchaSuccess] = useState(false);
  // useContext(AuthContext)
  const { authState, authActions } = React.useContext(AuthContext);
  // useState(). React["joku"] on turha, koska useState ja useContext molemmat mestoilla
  const [setting, setSetting] = React.useState({
    show_captcha: false,
    disable_registertion_from_others: false
  })

  // Laukeaa heti alussa, mutta uusimpien react dokkareiden mukaan tämä on väärä tapa tehdä asioita
  useEffect(() => {
    request()
      .get("/api/settings")
      .then(res => {
        if (res.status == 200) {
          const obj = {};
          for (let i = 0; i < res.data.data.length; i++) {
            const element = res.data.data[i];
            if (element.setting_value == "1") {
              obj[element.setting_key] = true
            }
            if (element.setting_value == "0") {
              obj[element.setting_key] = false
            }
          }
          setSetting(obj);
        }

      })
  }, [])

  /**
   * Pitkä selostus:
   * 1. npm i react-query
   * 2. npm i axios
   * 3. Luo kansiot: "requests" ja "hooks"
   * 4. Lisää request kansioon funktio
   *
   * export async function getSettings() {
   *  return axios.get(`${API_BASE_URL}/api/settings`)
   * }
   *
   * 5. Lisää hooks kansioon:
   * const useSettings = () => useQuery("settings", getSettings)
   *
   * 6. Käytä sitä tässä komponentissa vaikka näin:
   *
   * const settings = useSettings();
   *
   * if (settings.isLoading) return <LoadingPylpyra/>
   * if (settings.error) return <ErrorViesti/>
   * return (<NykyisetKomponentit><Formik initialValues={defaultValues}> {settings.data.disable_registertion_from_others && <FooBar/>}</Formik>)
   *
   * Jos käytät tätä workflowta, niin useQuery laukeaa välittömästi, kun sivu on latautunut. Saat tiedon, kun kyselyä tehdään ja kun se on valmis saat
   * heti tietoosi, että onko kysely onnistunut vai ei.
   *
   * Kun passaat JSON dataa API:n, niin voit käyttää useMutate() metodia.
   *
   * Ei enää koskaan useEffect(() => {}, []) fetchejä tai ylimääräisiä stateja, jotka pitää päivittää.
   *
   * Voit käyttää useEffectejä sitten react-queryn kanssa sitten, että pulttaat depsin kiinni ([settings.isLoading]]) isLoadingiin tai .dataan,
   * jonka jälkeen voit tutkailla paremmin, että onko kysely onnistunut. Myös responsen validaation voi toteuttaa tuossa vaiheessa.
   */

  return (
    <div className="d-flex justify-content-center">
      <div className="card col-12 col-lg-6 login-card mt-2">
        <div
          className="alert alert-success mt-2"
          style={{ display: state.successMessage ? "block" : "none" }}
          role="alert"
        >
          {state.successMessage}
        </div>
        {/**
         * initialValuesin voi lykätä suoraan constikssi ja passata tähän
         */}
        <Formik
          initialValues={{
            name: "",
            email: "",
            domain: "",
            password: "",
            confirmPassword: "",
          }}
          validationSchema={SignupSchema}
          onSubmit={(values, formProps) => {
            // if (agree). Koska agree on ilmeisesti boolean, niin voit käyttää shorthandia
            if (agree == true) {
              sendDetailsToServer(values, formProps);
            }
          }}
        >
          {setting.disable_registertion_from_others &&
                <div className="form-group text-left">
                  <TextInput
                    label={"Domain"}
                    name="domain"
                  />
                  <small id="domainHelp" className="form-text text-muted">
                    You need to know right domain that is in use.
                  </small>
                </div>
                }
        </Formik>
      </div>
    </div>
  );
};

carabia [13.04.2023 17:12:24]

#

noutti kirjoitti:

carabia kirjoitti:

(11.04.2023 12:20:37): Valuutta siis kannattaa vuotaa maasta ulos...

Kannattaa vetää se pää ulos perseestä välillä.

Kiitoksia hyvästä ja rakentavasta palautteesta. Argumentaation, ja ehkä myös luetun ymmärtämisen kanssa herralla lienee ongelmia, kehottaisin korjaamaan asian ennenkuin ryhdyt puuhiin seuraavan jahweskripti freimvörkin kanssa.

noutti [13.04.2023 19:03:06]

#

carabia kirjoitti:

(13.04.2023 17:12:24): ”– –” Kiitoksia hyvästä ja rakentavasta palaut­teesta...

Suosittelen sinulle samaa, kun joskus pääset työelämään kiinni.

React ei ole javascript framework.

btw. 10$ tunnihinnalla ei kannata hirveästi keulia Mika. Tai olla rasisti. Edes ohjelmointiputkassa.

muuskanuikku [13.04.2023 19:08:24]

#

noutti kirjoitti:

carabia kirjoitti:

(13.04.2023 17:12:24): ”– –” Kiitoksia hyvästä ja rakentavasta palaut­teesta...

Suosittelen sinulle samaa, kun joskus pääset työelämään kiinni.

React ei ole javascript framework.

Jahvestahan tässä puhuttiin. Taipskröpt on muuten vain syntaksista sokuria javascriptille.

noutti [13.04.2023 19:18:31]

#

muuskanuikku kirjoitti:

(13.04.2023 19:08:24): ”– –” Jahvestahan tässä puhuttiin. Taipskröpt on...

Odotas kun kuulet coffeescriptistä

walkout_ [21.04.2023 00:26:41]

#

noutti kirjoitti:

(13.04.2023 19:03:06): ”– –” Suosittelen sinulle samaa, kun joskus pääset...

Jaa no kun Upwork:issä laittaa ilmoituksen paikasta niin voi valita joko tuntihinnan tai fixed price:n, eli urakkapalkkion freelancerille. Ja kun ilmoituksen laittaa niin tulee tarjouksia jo ensimmäisten minuuttien aikana useita ulkomailta, kuten Canadsta, USAsta, Intiasta, Arabiasti ja vaikka mistä.

Jotkut tekee $3 / tunti jotkut taas $80 / tunti riippumatta kotimaasta.


Sivun alkuun

Vastaus

Aihe on jo aika vanha, joten et voi enää vastata siihen.

Tietoa sivustosta