LoginSignup
1
0

More than 1 year has passed since last update.

Rails×Reactでユーザー画面の色をアカウントごとに切り替える

Posted at

はじめに

SaaS型プロダクトで、管理画面側(Shop)とエンドユーザー側(User)との2つがあるプロダクトを開発しています。管理画面側(Shop)は、Shopアカウントごとにログインを行います。
Ruby on RailsとReact(TypeScript)、Material-UIで開発しています。

やりたいこと

アカウントごとにそれぞれ別の色を設定し、それが各アカウントごとのエンドユーザー側の画面のマスター色に反映されるようにしたい。
例: アカウントA(ShopA)の色は赤色、アカウントB(ShopB)の色は青色。ユーザーはShopAのエンドユーザー画面に入ると赤色がマスター色(ヘッダーやボタンなど)、ShopBのエンドユーザー画面は青色がマスター色。

方針

  1. Shop_colorテーブルを追加、ShopテーブルがShop_colorテーブルを1つ持つ(has_one)
  2. カラーコード(例:#FFFFFF)を一旦追加。
  3. RailsControllerで、ShopのShop_colorを取得しReact側に送信、Shop_colorがnullであればデフォルトを代入
  4. React側で受け取ったShop_colorをボタンやヘッダーなどの色に指定する

最初は、CSS変数(カスタムプロパティ)とMaterial-UIのThemeTemplateで対処しようとしていたのですが、Propsで渡す方が楽なのでpropsで処理することにしました。

実装

1. Shop_colorテーブルを追加。

console
rails g model ShopColor shop_id:string color_code:string

以下のmigrationファイルが生成。

migration
class CreateShopColors < ActiveRecord::Migration[6.0]
  def change
    create_table :shop_colors do |t|
      t.integer :shop_id
      t.string :color_code

      t.timestamps
    end
  end
end

モデルではshopにbelongs_to、shop側ではhas_oneさせる。

shop_color.rb
class ShopColor < ApplicationRecord
    belongs_to :shop
end
shop.rb
class Shop < ApplicationRecord
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable

  省略
  has_one :shop_color
end

migrationファイルをあげる。

console
bundle exec rake db:migrate

2. カラーコードを一旦追加

カラーコード を一旦手動でDBに登録

console
rails c 
 > a = ShopColor.new
 > a.shop_id = 1
 > a.color_code = "#AAAAAA" #カラーコード
 > a.save!

3. RailsControllerの処理

UserController
#省略
def shop_show
    @target_shop = Shop.find_by(id: params[:shop_id])
    @shop_color = @target_shop.shop_color.color_code ||= "#ABCDEF"  #shop_color.color_codeがない場合用にデフォルトのカラーコード を右辺に
end
#省略

4. React側の処理

shop_show.html.erb
<%= react_component("templates/users/user_managements/shop_menu", {
    shop: @target_shop,
    shopColor: @shop_color,
    #省略
}) %>
shop_show.tsx


type Props = {
  shop: {
    id: number
    name: string
  }
  shopColor: string
}

//クラスで指定する場合
const useStyles = makeStyles<Theme, Props>((theme: Theme) =>
  createStyles({
    button: {
      backgroundColor:  (props)=> props.shopColor,
    },
  })
 )

//returnの中で書き込む場合
const ShopShow: React.FC<Props> = (props: Props) => {
const classes = useStyles(props);
 return (
 <ThemeTemplate>
  <Typography style={{color: props.shopColor}}>
   Hello
  </Typography>
  <Button className={classes.button} > 
    クラス指定のボタン
  </Button>
 </ThemeTemplate>
 )
}

export default ShopShow

ヘッダーなどのAppBarで利用する場合は、呼び出す際にpropsで渡す。Appbar.tsx側でも上記と同様に処理

xxx

<AppBarUserComponent isSignedIn={props.isSignedIn} shop={props.shop} shopColor={props.shopColor}/>

処理の流れ

  1. UserControllerでshop_showメソッドが呼ばれる。@shop_colorにカラーコード を詰める
  2. shop_show.html.erbが呼ばれ、@shop_colorshopColorでreactコンポーネントのshop_menu.tsxに渡す
  3. shop_menu.tsxではPropsshopColorの型を用意。
  4. shop_menu.tsxのconst ShopShow: React.FC<Props> = (props: Props) =>の最初で、const classes = useStyles(props);propsuseStylesに渡す。
  5. shop_menu.tsxのuseStylesで、makeStyles<Theme, Props>Propsを受け取り、backgroundColor: (props)=> props.shopColorで色を指定する

おわりに

ユーザーごとに背景色を変えるなどの処理は良くあるかと思いますので参考になれば嬉しいです。

参考

reactjs : TSのmakeStyleに小道具を渡す

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0