<h1>Full data</h1>

<pre id="data-full"></pre>

<h1>Redacted data</h1>
<pre id="data-redacted"></pre>
* {
  box-sizing: border-box;
}

body {
  padding: 2rem;
  min-width: 360px;
}

h1 {
  margin-top: 0;
}

pre {
  display: block;
  background-color: #eee;
  margin-bottom: 2rem;
  padding: 1rem;
  width: 100%;
  white-space: normal;
  overflow: auto;
  max-width: 100%;
}
/* SAMPLE DATA */

const USER = {
  firstName: "John",
  middleName: "",
  lastName: "Doe",
  email: "john.doe@email.com",
  balance: 2649.53,
  currency: "USD",
  locale: "en-US"
};

/* UTILS */
const getFullName = (firstName, lastName, middleName) =>
  [firstName, middleName, lastName].filter((n) => !!n).join(" ");

const getFormattedBalance = (locale, currency, value) => {
  return new Intl.NumberFormat(locale, {
    style: "currency",
    currency
  }).format(value);
};

const getRedactedEmail = (email) => {
  const [name, ...rest] = email.split("@");
  const [service, domain] = rest.join("").split(".");

  const redactedName = `${name[0]}*****${name[name.length - 1]}`;
  const redactedDomain = `${service[0]}***${
    service[service.length - 1]
  }.${domain}`;

  return `${redactedName}@${redactedDomain}`;
};

const getRedactedName = (name) => (Boolean(name.length) ? `${name[0]}.` : "");

/* PROXY */

const handleFullGet = (obj, prop) => {
  if (prop === "fullName") {
    return getFullName(
      Reflect.get(obj, "firstName"),
      Reflect.get(obj, "lastName"),
      Reflect.get(obj, "middleName")
    );
  }

  if (prop === "balance") {
    return getFormattedBalance(
      Reflect.get(obj, "locale"),
      Reflect.get(obj, "currency"),
      Reflect.get(obj, "balance")
    );
  }

  if (!(prop in obj)) {
    console.error(`${prop.toString()} doesn't exist in object`, obj);
    return;
  }

  return Reflect.get(obj, prop);
};

const createUserDataProxy = (user) => {
  const proxy = new Proxy(user, {
    get: handleFullGet
  });

  return proxy;
};

const handleRedactedGet = (obj, prop) => {
  if (prop === "fullName") {
    return getFullName(
      Reflect.get(obj, "firstName"),
      getRedactedName(Reflect.get(obj, "lastName")),
      getRedactedName(Reflect.get(obj, "middleName") || "")
    );
  }

  if (prop === "middleName") {
    return getRedactedName(Reflect.get(obj, "middleName"));
  }

  if (prop === "lastName") {
    return getRedactedName(Reflect.get(obj, "lastName"));
  }

  if (prop === "email") {
    return getRedactedEmail(Reflect.get(obj, "email"));
  }

  if (!(prop in obj)) {
    console.error(`${prop} doesn't exist in object`, obj);
    return;
  }

  return "Data not available";
};

const createRedactedDataProxy = (user) => {
  const proxy = new Proxy(user, {
    get: handleRedactedGet
  });

  return proxy;
};

/* APPLY PROXY */

const userFull = createUserDataProxy(USER);
const userRedacted = createRedactedDataProxy(USER);

/* OUTPUT */

const containerFull = document.getElementById("data-full");
const containerRedacted = document.getElementById("data-redacted");

containerFull.append(userFull.fullName);
containerFull.append(document.createElement("br"));
containerFull.append(userFull.email);
containerFull.append(document.createElement("br"));
containerFull.append(userFull.balance);

containerRedacted.append(userRedacted.fullName);
containerRedacted.append(document.createElement("br"));
containerRedacted.append(userRedacted.email);
containerRedacted.append(document.createElement("br"));
containerRedacted.append(userRedacted.balance);
containerRedacted.append(document.createElement("br"));

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.